diff --git a/Enum.h b/Enum.h new file mode 100644 index 0000000..eb68de6 --- /dev/null +++ b/Enum.h @@ -0,0 +1,99 @@ +/// @file Enum.h +/// Enum type generator. +/// +/// @todo Provide type name as a string. + + + +#pragma once + +#include + + + +// 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 { \ + protected: \ + using _Super = _enum::_Internal; \ + \ + 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 \ + 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 \ + explicit EnumType(IntegralType value, \ + typename enable_if::value> \ + ::type *dummy = nullptr) : _value(value) { } \ + \ + template \ + 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"); diff --git a/EnumInternal.h b/EnumInternal.h new file mode 100644 index 0000000..3a03ad2 --- /dev/null +++ b/EnumInternal.h @@ -0,0 +1,1255 @@ +/// @file EnumInternal.h +/// Internal definitions for the enum type generator in `Enum.h`. +/// +/// Several definitions must precede the public `ENUM` macro and the interface +/// defined in it. This includes helper classes and all `constexpr` functions, +/// which cannot be forward-declared. In order to make `Enum.h` more readable, +/// these definitions are placed into this file, which is included from +/// `Enum.h`. +/// +/// Throughout the internal code, macro and template parameters named `EnumType` +/// stand for the class types generated by the `ENUM` macro, while parameters +/// named `EnumValue` stand for the internal C++ enum types. Roughly, +/// `EnumValue == EnumType::_Value`. +/// +/// @todo Consider simplifying compile-time function signatures by combining +/// arguments that don't change into a single `constexpr` object. +/// @todo There is a way to perform all computation on the names and values +/// arrays in a single pass, by requiring that all the special constants +/// (such as `_bad`) appear at the end, and working back to front. It's not +/// clear what kind of performance improvement this will give, as the +/// current passes are already pretty fast, and the compile time is +/// dominated by parsing and type checking of other code. +/// @todo It's possible that reducing the number of redundant array accesses +/// will improve compile time, but a stand-alone test suggests that the cost +/// of these accesses is very small. +/// @todo Generating the values array using the `_eat_assign` template is +/// expensive, and the cost seems to be due to the instantiation of +/// compile-time objects, not due to templates. Trying statement expressions +/// (a GNU extension) didn't work, because statement expressions aren't +/// allowed "at file scope" (in this case, within a class type declared at +/// file scope). +/// @todo `_enum::_special_names::_find` can terminate early after finding all +/// four special names' indices. +/// @todo Compile time is currently dominated by the cost of static +/// instantiation. Try to reduce this cost by statically instantiating data +/// structures for each type, then dynamically passing them to a small +/// number of actual processing functions - which only have to be +/// instantiated once for every different underlying type. Underlying types +/// are very likely to collide. + + + +#pragma once + +#include // For size_t. +#include // For string and memory routines. +#include "util/EnumPreprocessorMap.h" + + + +/// Internal namespace for compile-time and private run-time functions used by +/// the enum class generator. +namespace _enum { + + + +/// Weak symbols to allow the same data structures to be defined statically in +/// multiple translation units, then be collapsed to one definition by the +/// linker. +#define _ENUM_WEAK __attribute__((weak)) + + + +// Forward declaration of _Internal, for use in a friend declation in _Iterable. +template class _Internal; + +/// Template for iterable objects over enum names and values. +/// +/// The iterables are intended for use with C++11 `for-each` syntax. They are +/// returned by each enum type's static `names()` and `values()` methods. For +/// example, `EnumType::values()` is an iterable over valid values of type +/// `EnumType`, and allows the following form: +/// +/// ~~~{.cc} +/// for (EnumType e : EnumType::values()) { +/// // ... +/// } +/// ~~~ +/// +/// The iterable class is templated to reuse code between the name and value +/// iterables. +/// +/// @tparam Element Type of element returned during iteration: either the enum +/// type (for iterables over `values()`) or `const char*` (for iterables +/// over `names()`). +/// @tparam EnumType The enum type. +/// @tparam ArrayType Type of the array actually being iterated over. The reason +/// this is a type parameter is because for the iterable over `values()`, +/// the underlying array type is `const EnumType::_value * const`, instead +/// of `const EnumType * const`, as one might first expect. Objects of type +/// `EnumType` are constructed on the fly during iteration from values of +/// type `EnumType::_value` (this is a no-op at run-time). For iterables +/// over `names()`, `ArrayType` is simply `const char * const`, as would be +/// expeted. +/// +/// @todo Consider making `_Iterable` `constexpr`. +/// @todo An iterator over valid values and an iterator over all values should +/// really be different types. +/// +/// @internal +/// +/// An `_Iterable` stores a reference to the array (of either names or values) +/// that will be iterated over. `_Iterable::iterator` additionally stores an +/// index into the array. The iterator begins at the first valid index. Each +/// time it is incremented, the iterator advances to the next valid index. The +/// `end()` iterator stores an index equal to the size of the array. Values are +/// considered valid if they are not equal to the bad value, are not below the +/// minimum value, and are not above the maximum value. Names are valid if they +/// are the name of a valid value. +template +class _Iterable { + public: + /// Iterators for iterating over enum names or values. + class iterator { + public: + /// Returns the current name or value. + Element operator *() const { return (Element)_arrayPointer[_index]; } + + /// Advances the iterator to the next valid name or value. If there is + /// no such value, the iterator becomes equal to the result of + /// `_Iterable::end()`. + /// @return A reference to itself. + iterator& operator ++() + { + if (_allValues) { + if (_index < EnumType::_rawSize) { + do { + ++_index; + } while(_index < EnumType::_rawSize && + EnumType::_isSpecialIndex(_index)); + } + } + else { + if (_index <= EnumType::_highestValidIndex) { + do { + ++_index; + } while(_index <= EnumType::_highestValidIndex && + !EnumType::_isIterableIndex(_index)); + } + } + + return *this; + } + + /// Compares two iterators for equality. + /// @param other Another iterator over the same array. + bool operator ==(const iterator &other) const + { + return (other._arrayPointer == _arrayPointer) && + (other._index == _index); + } + + /// Compares two iterators for equality - negated comparison. + /// @param other Another iterator over the same array. + bool operator !=(const iterator &other) const + { return !(*this == other); } + + public: + /// An iterator can be declared without initialization - in this case, + /// its state is undefined. + iterator() = default; + + private: + /// Constructs an iterator over the given array, with the given starting + /// index. This method is used only be the enclosing `_Iterable` class. + /// @param arrayPointer Array that will be iterated over. + /// @param allValues If `true`, the iterator "stops" at all values, + /// whether they are valid or not. Otherwise, the iterator stops + /// only at valid values (or their names). + /// @param index Initial index into the array. This must be the index of + /// a valid value. + iterator(ArrayType arrayPointer, bool allValues, size_t index) : + _arrayPointer(arrayPointer), _allValues(allValues), + _index(index) { } + + /// Reference to the array being iterated. + ArrayType _arrayPointer; + /// Whether to return only valid values or all values. + bool _allValues; + /// Current index into the array. This is always either the index of a + /// valid value or else it is equal to the size of the array. + size_t _index; + + /// Permit `_Iterable` to create iterators. + friend class _Iterable; + }; + + /// Returns an iterator to the beginning of the name or value array. + iterator begin() const + { + if (_allValues) { + size_t firstIndex = 0; + + while (firstIndex < EnumType::_rawSize && + EnumType::_isSpecialIndex(firstIndex)) { + + ++firstIndex; + } + + return iterator(_arrayPointer, true, firstIndex); + } + else { + size_t firstIndex = EnumType::_lowestValidIndex; + + while ((firstIndex <= EnumType::_highestValidIndex) && + !EnumType::_isIterableIndex(firstIndex)) { + + ++firstIndex; + } + + return iterator(_arrayPointer, false, firstIndex); + } + } + + /// Returns an iterator to the end of the name or value array. + iterator end() const + { + if (_allValues) + return iterator(_arrayPointer, true, EnumType::_rawSize); + else { + return iterator(_arrayPointer, false, + EnumType::_highestValidIndex + 1); + } + } + + /// Returns the number of valid elements (names or values) in the iterable - + /// the number of times an iterator starting at `begin()` can be + /// dereferenced and then advanced before reaching `end()`. + size_t size() const { return EnumType::size(); } + + private: + /// Creates an `_Iterable` object over an array. + _Iterable(ArrayType arrayPointer, bool allValues) : + _arrayPointer(arrayPointer), _allValues(allValues) { } + + /// The array over which iteration will be performed. + ArrayType _arrayPointer; + /// Whether to return only valid values or all values. + bool _allValues; + + /// Permit the enum class itself to create `_Iterable` objects. + friend class _Internal; +}; + + + +/// Compile-time helper class used to transform expressions of the forms `A` and +/// `A = 42` into values of type `UnderlyingType` that can be used in +/// initializer lists. The `ENUM` macro is passed a mixture of simple enum +/// constants (`A`) and constants with an explicitly-assigned value (`A = 42`). +/// Both must be turned into expressions of type `UnderlyingType` in order to be +/// usable in initializer lists of the values array. This is done by prepending +/// a cast to the expression, as follows: +/// ~~~{.cc} +/// (_eat_assign)A +/// (_eat_assign)A = 42 +/// ~~~ +/// The second case is the interesting one. At compile time, the value `A` is +/// first converted to an equivalent `_eat_assign` object, that +/// stores the value. This object has an overriden assignment operator, which +/// "eats" the `= 42` and returns the stored value of `A`, which is then used in +/// the initializer list. +/// @tparam UnderlyingType Final type used in the values array. +template +class _eat_assign { + private: + UnderlyingType _value; + + public: + explicit constexpr _eat_assign(UnderlyingType value) : _value(value) { } + constexpr UnderlyingType operator =(UnderlyingType dummy) + { return _value; } + constexpr operator UnderlyingType () { return _value; } +}; + +/// Prepends its second argument with the cast `(_eat_assign)` +/// in order to make it usable in initializer lists. See `_eat_assign`. +#define _ENUM_EAT_ASSIGN_SINGLE(UnderlyingType, expression) \ + ((_enum::_eat_assign)expression) + +/// Prepends each of its arguments with the casts +/// `(_eat_assign)`, creating the elements of an initializer +/// list of objects of type `UnderlyingType`. +#define _ENUM_EAT_ASSIGN(UnderlyingType, ...) \ + _ENUM_PP_MAP(_ENUM_EAT_ASSIGN_SINGLE, UnderlyingType, __VA_ARGS__) + + + +/// Stringizes its second argument. The first argument is not used - it is there +/// only because `_ENUM_PP_MAP` expects it. +#define _ENUM_STRINGIZE_SINGLE(ignored, expression) #expression + +/// Stringizes each of its arguments. +#define _ENUM_STRINGIZE(...) \ + _ENUM_PP_MAP(_ENUM_STRINGIZE_SINGLE, ignored, __VA_ARGS__) + + + +/// Symbols that end a constant name. Constant can be defined in several ways, +/// for example: +/// ~~~{.cc} +/// A +/// A = AnotherConstant +/// A = 42 +/// A=42 +/// ~~~ +/// These definitions are stringized in their entirety by `_ENUM_STRINGIZE`. +/// This means that in addition to the actual constant names, the raw `_names` +/// arrays potentially contain additional trailing symbols. `_ENUM_NAME_ENDERS` +/// defines an array of symbols that would end the part of the string that is +/// the actual constant name. Note that it is important that the null terminator +/// is implicitly present in this array. +#define _ENUM_NAME_ENDERS "= \t\n" + +/// Compile-time function that determines whether a character terminates the +/// name portion of an enum constant definition. +/// +/// Call as `_endsName(c)`. +/// +/// @param c Character to be tested. +/// @param index Current index into the `_ENUM_NAME_ENDERS` array. +/// @return `true` if and only if `c` is one of the characters in +/// `_ENUM_NAME_ENDERS`, including the implicit null terminator in that +/// array. +constexpr bool _endsName(char c, size_t index = 0) +{ + return + // First, test whether c is equal to the current character in + // _ENUM_NAME_ENDERS. In the case where c is the null terminator, this + // will cause _endsName to return true when it has exhausted + // _ENUM_NAME_ENDERS. + c == _ENUM_NAME_ENDERS[index] ? true : + // If _ENUM_NAME_ENDERS has been exhausted and c never matched, return + // false. + _ENUM_NAME_ENDERS[index] == '\0' ? false : + // Otherwise, go on to the next character in _ENUM_ENDERS. + _endsName(c, index + 1); +} + +/// Compile-time function that matches a stringized name (with potential +/// trailing spaces and equals signs) against a reference name (a regular +/// null-terminated string). +/// +/// Call as `_namesMatch(stringizedName, referenceName)`. +/// +/// @param stringizedName A stringized constant name, potentially terminated by +/// one of the symbols in `_ENUM_NAME_ENDERS` instead of a null terminator. +/// @param referenceName A name of interest. Null-terminated. +/// @param index Current index into both names. +/// @return `true` if and only if the portion of `stringizedName` before any of +/// the symbols in `_ENUM_NAME_ENDERS` exactly matches `referenceName`. +constexpr bool _namesMatch(const char *stringizedName, + const char *referenceName, + size_t index = 0) +{ + return + // If the current character in the stringized name is a name ender, + // return true if the reference name ends as well, and false otherwise. + _endsName(stringizedName[index]) ? referenceName[index] == '\0' : + // The current character in the stringized name is not a name ender. If + // the reference name ended, then it is too short, so return false. + referenceName[index] == '\0' ? false : + // Neither name has ended. If the two current characters don't match, + // return false. + stringizedName[index] != + referenceName[index] ? false : + // Otherwise, if the characters match, continue by comparing the rest of + // the names. + _namesMatch(stringizedName, referenceName, index + 1); +} + + + +/// Represents invalid indices into the enum names and values arrays. +#define _ENUM_NOT_FOUND ((size_t)-1) + + + +/// Functions and types used to search for the indices of special names (such as +/// `_bad`.) The main purpose of this namespace is to shorten the identifiers +/// used in the implementation of the search function. +namespace _special_names { + +/// Name of the special constant for declaring the invalid value. +#define _ENUM_BAD "_bad" +/// Name of the special constant for declaring the default value. +#define _ENUM_DEF "_def" +/// Name of the special constant for declaring the minimum value. +#define _ENUM_MIN "_min" +/// Name of the special constant for declaring the maximum value. +#define _ENUM_MAX "_max" + +#define _ENUM_SPECIAL_COUNT 4 + +/// Data returned by the `_enum::_special_names::_find` function. `_find` +/// returns the index into the names array at which each one of `_bad`, `_def`, +/// `_min`, and `_max` was found, or `_ENUM_NOT_FOUND` for each special name +/// that wasn't found. It also returns the number of times each special name was +/// found. During one run of `_find` on a correct enum declaration, an +/// `_Indices` object is created at most five times. The last `_Indices` object +/// is returned to the caller by copy. +class _Indices { + public: + /// Last found indices for each of the special constants. + size_t bad, def, min, max; + + /// Number of times each special constant was seen. + int numberBad, numberDef, numberMin, numberMax; + + /// Creates the initial `_Indices` object, when no special names have been + /// found. + constexpr _Indices() : + bad(_ENUM_NOT_FOUND), def(_ENUM_NOT_FOUND), + min(_ENUM_NOT_FOUND), max(_ENUM_NOT_FOUND), + numberBad(0), numberDef(0), numberMin(0), numberMax(0) { } + + private: + /// Constructor used internally by the `foundXYZ` methods, each called when + /// one of the special names is encountered. Sets the fields of the + /// `_Indices` object. + constexpr _Indices(size_t _bad, size_t _def, size_t _min, size_t _max, + int _numberBad, int _numberDef, + int _numberMin, int _numberMax) : + bad(_bad), def(_def), min(_min), max(_max), + numberBad(_numberBad), numberDef(_numberDef), + numberMin(_numberMin), numberMax(_numberMax) { } + + public: + /// Called by `_find` when `_bad` is found. Sets the index of the last match + /// for `_bad` to the given index, and increments the number of times `_bad` + /// has been found. Returns a new `_Indices` object reflecting this change. + /// @param index Index at which `_bad` was found in the names array. + /// @return The new `_Indices` object. + constexpr const _Indices foundBad(size_t index) + { return _Indices(index, def, min, max, + numberBad + 1, numberDef, numberMin, numberMax); } + + /// Called by `_find` when `_def` is found. + /// @see `foundBad` + constexpr const _Indices foundDef(size_t index) + { return _Indices(bad, index, min, max, + numberBad, numberDef + 1, numberMin, numberMax); } + + /// Called by `_find` when `_min` is found. + /// @see `foundBad` + constexpr const _Indices foundMin(size_t index) + { return _Indices(bad, def, index, max, + numberBad, numberDef, numberMin + 1, numberMax); } + + /// Called by `_find` when `_max` is found. + /// @see `foundBad` + constexpr const _Indices foundMax(size_t index) + { return _Indices(bad, def, min, index, + numberBad, numberDef, numberMin, numberMax + 1); } +}; + +/// Compile-time function that returns the indices of constants named `_bad`, +/// `_def`, `_min`, and `_max`, if they are present, and the number of times +/// each index was found. The search is done back-to-front, so that future +/// versions of this function can take advantage of the likelihood that all the +/// special names are found at the end of the enum declaration, and terminate +/// early. +/// +/// Call as `_find(names, array_size - 1)`. +/// +/// @param names Enum constant names array. +/// @param index Current index into the names array. +/// @param indices Current search results. +/// @return An `_Indices` object representing the search results. +constexpr _Indices _find(const char * const *names, size_t index, + const _Indices &indices = _Indices()) +{ + return + // If the index has been advanced (backward) to past the beginning of + // the array, return the current search results by copy. + index == (size_t)-1 ? indices : + // The index is valid. As an optimization, check if the current name + // begins with an underscore. If not, immediately go on to the next + // index (in a backwards direction). + names[index][0] != '_' ? + _find(names, index - 1, indices) : + // The index is valid and the name begins with an underscore. Compare + // the entire name with each of the potential special names. If there is + // a match, continue at next index with an updated _Indices object. + // Otherwise, try the next special name. + _namesMatch(names[index], _ENUM_BAD) ? + _find(names, index - 1, indices.foundBad(index)) : + _namesMatch(names[index], _ENUM_DEF) ? + _find(names, index - 1, indices.foundDef(index)) : + _namesMatch(names[index], _ENUM_MIN) ? + _find(names, index - 1, indices.foundMin(index)) : + _namesMatch(names[index], _ENUM_MAX) ? + _find(names, index - 1, indices.foundMax(index)) : + // If the name did not match any of the special names, continue at the + // next index into the names array (in a backwards direction) with the + // current indices object unchanged. + _find(names, index - 1, indices); +} + +} + + + +/// Compile-time function that determines whether a given index is one of the +/// indices in `specialIndices`. After the enum generator finds the special +/// names using `_enum::_special_names::_find`, it puts the four indices into an +/// array of length 4. Indices for special names that weren't found are set to +/// `_ENUM_NOT_FOUND`. Other functions, that run later, need to know whether +/// they are dealing with one of these special indices or not. This function +/// exists for that purpose. +/// +/// Call as `_isSpecial(specialIndices, specialIndexCount, someIndex)`. +/// +/// @param specialIndices Array of special indices. +/// @param specialIndexCount Number of special indices. +/// @param candidate A candidate index. +/// @param index Current index into `specialIndices`. +constexpr bool _isSpecial(const size_t *specialIndices, + size_t specialIndexCount, size_t candidate, + size_t index = 0) +{ + return + // If the index into specialIndices is equal to the number of such + // special indices, then the candidate index was not found, so return + // false. + index == specialIndexCount ? false : + // index is less than the count of special indices. If the candidate is + // equal to the current special index, return true. + candidate == specialIndices[index] ? true : + // Otherwise, continue to the next special index. + _isSpecial(specialIndices, specialIndexCount, candidate, index + 1); +} + +/// Compile-time function that determines whether the value at one index is also +/// present at another index in the enum values array by searching forward. +/// Special constants such as `_bad` must be set to the value of another, +/// non-special constant that is also declared in the enum type. This function +/// and `_resolveReverse` check for this requirement by finding another index +/// with the same value as the given index. `_resolveForward` is used for values +/// that are likely to be found near the beginning of the enum declaration: +/// `_min` and `_def`. +/// +/// Call as `_resolveForward(values, count, special, specialCount, value)`. +/// +/// @tparam UnderlyingType Type of elements in the values array. +/// @param values Enum values array. +/// @param valueCount Number of elements in `values`. +/// @param specialIndices Special indices array. See `_isSpecial`. This array is +/// used to reject values that are found at special indices - the value +/// being resolved must be found at a non-special index. +/// @param specialIndexCount Number of elements in `specialIndices`. +/// @param specialValue Value to be resolved. +/// @param index Current index into the `values` array. +/// @return The non-special index at which `specialValue` is found, or +/// `_ENUM_NOT_FOUND` if it is not found at all. +template +constexpr size_t _resolveForward(const UnderlyingType *values, + size_t valueCount, + const size_t *specialIndices, + size_t specialIndexCount, + UnderlyingType specialValue, size_t index = 0) +{ + return + // If iteration has reached the end of the values array, then the value + // has not been found. + index == valueCount ? _ENUM_NOT_FOUND : + // index still points into the array. If the value at the index is equal + // to the special value, and this is not a special index, then return + // the index. + values[index] == specialValue && + !_isSpecial(specialIndices, specialIndexCount, index) + ? index : + // Otherwise, continue at the next index into the values array. + _resolveForward(values, valueCount, specialIndices, specialIndexCount, + specialValue, index + 1); +} + +/// Compile-time function that resolves special values in a backwards direction. +/// +/// Call as `_resolveReverse(values, count, special, specialCount, value, +/// count - 1)`. +/// +/// @see `_resolveForward` +template +constexpr size_t _resolveReverse(const UnderlyingType *values, + const size_t *specialIndices, + size_t specialIndexCount, + UnderlyingType specialValue, size_t index) +{ + return + // The index is assumed to be valid upon entry into this function. + // Immediately perform the same check as in _resolveForward. + values[index] == specialValue && + !_isSpecial(specialIndices, specialIndexCount, index) + ? index : + // If the value was not found at the current index, then, if the current + // index is zero, the value is not present in values. + index == 0 ? _ENUM_NOT_FOUND : + // Otherwise, continue at the next (in a backwards direction) index into + // the values array. + _resolveReverse(values, specialIndices, specialIndexCount, + specialValue, index - 1); +} + + + +/// Compile-time function that returns the highest index lower than the initial +/// value of `index` that is not a special index. Used to find the bad value if +/// it is not explicitly given by supplying the `_bad` constant. +/// +/// Call as `_highestRegular(special, specialCount, valueCount - 1)`. +/// +/// @param specialIndices Array of special indices (indices of `_bad`, etc.) +/// @param specialIndexCount Number of elements in `specialIndices`. +/// @param index Current candidate index. This starts at the number of enum +/// constants, minus one, and decreases until an index that is not in +/// `specialIndices` is found. +constexpr size_t _highestRegular(const size_t *specialIndices, + size_t specialIndexCount, size_t index) +{ + return + // The current index is assumed to be valid. If it's not a special + // index, return it. + !_isSpecial(specialIndices, + specialIndexCount, index) ? index : + // If it's a special index and is zero, there are no lower non-special + // indices - return _ENUM_NOT_FOUND. + index == 0 ? _ENUM_NOT_FOUND : + // Otherwise, continue the search at the next-lowest index. This cannot + // happen more than four times because there are at most four special + // indices. + _highestRegular(specialIndices, specialIndexCount, index - 1); +} + + + +/// Compile-time function that finds the lowest index that is not a special +/// index, and is not the index of the bad value. The bad value is the one that +/// is either set by `_bad`, or, if `_bad` is not given, it is the last regular +/// (non-special) value declared in the enum type. +/// +/// Call as `_lowestValid(values, count, special, specialCount, badValue)`. +/// +/// @tparam UnderlyingType Type of elements in the values array. +/// @param values Values array. +/// @param valueCount Number of elements in the values array. +/// @param specialIndices Special index array. +/// @param specialIndexCount Number of elements in `specialIndices`. +/// @param badValue The bad value. +/// @param index Current index into `values`. +template +constexpr size_t _lowestValid(const UnderlyingType *values, size_t valueCount, + const size_t *specialIndices, + size_t specialIndexCount, UnderlyingType badValue, + size_t index = 0) +{ + return + // If the values array has been exhausted without finding a valid index, + // return _ENUM_NOT_FOUND. + index == valueCount ? _ENUM_NOT_FOUND : + // The values array has not been exhausted. If the current index is not + // special, and the value at the index is not the bad value, return the + // index. + !_isSpecial(specialIndices, specialIndexCount, index) && + values[index] != badValue ? index : + // Otherwise, continue at the next index in the values array. + _lowestValid(values, valueCount, specialIndices, specialIndexCount, + badValue, index + 1); +} + + + +/// Compile-time function that finds the highest index that is not a special +/// index, and is not the index of the bad value. +/// +/// Call as `_highestValid(values, special, specialCount, badValue, +/// valueCount - 1)`. +/// +/// @see `_lowestValid` +template +constexpr size_t _highestValid(const UnderlyingType *values, + const size_t *specialIndices, + size_t specialIndexCount, + UnderlyingType badValue, size_t index) +{ + return + // The index is assumed to be in range upon entry into this function. If + // it's not a special index, nor is the value at the index equal to the + // bad value, return the index. + !_isSpecial(specialIndices, specialIndexCount, index) && + values[index] != badValue ? index : + // Otherwise, if the index has reached zero, a valid index will not be + // found. + index == 0 ? _ENUM_NOT_FOUND : + // The index is not valid and greater than zero - continue at the next + // (decreasing) index into the values array. + _highestValid(values, specialIndices, specialIndexCount, badValue, + index - 1); +} + + + +/// Functions and types used to compute range properties such as the minimum and +/// maximum declared enum values, and the total number of valid enum values. +namespace _range { + +/// Type of object returned by `_minMax`. Pair of the minimum and maximum value +/// found. +class _MinMax { + public: + size_t min, max; + + constexpr _MinMax(size_t _min, size_t _max) : + min(_min), max(_max) { } +}; + +/// Compile-time function that finds the default minimum and maximum values of +/// an enum. Note that if the minimum and/or maximum value is overridden using +/// `_min` and `_max`, the corresponding result of this function will be +/// ignored. +/// +/// This function should be called with `bestMin` and `bestMax` set to the first +/// valid (non-special, non-bad) index in the enumeration. One such index is +/// guaranteed to exist by code that runs prior to where this function is +/// called. +/// +/// @tparam UnderlyingType The enum underlying type. Comparisons are done at +/// this type. Note that the signedness of this type affects the +/// comparisons. +/// @param values Enum values array. +/// @param valueCount Number of values. +/// @param specialIndices Special index array. +/// @param specialIndexCount Number of special indices. +/// @param badValue The bad value. +/// @param index Current index in the iteration. This should initially be set to +/// the index after the first valid index (add one to it). +/// @param bestMin Index of the lowest valid value found so far. +/// @param bestMax Index of the highest valid value found so far. +template +constexpr _MinMax _minMax(const UnderlyingType *values, size_t valueCount, + const size_t *specialIndices, + size_t specialIndexCount, UnderlyingType badValue, + size_t index, size_t bestMin, size_t bestMax) +{ + return + // If the current index is at the end of the array, return the pair of + // the best found minimum and maximum. + index == valueCount ? _MinMax(bestMin, bestMax) : + // If the current is index is special (is _bad, _def, _min, or _max), or + // if the value at the current index is equal to the bad value, then + // skip the current index - go on to the next one without updating the + // min or max. + _isSpecial(specialIndices, specialIndexCount, index) || + values[index] == badValue ? + _minMax(values, valueCount, specialIndices, specialIndexCount, + badValue, index + 1, bestMin, bestMax) : + // If the current value is higher than the best max so far, continue at + // the next index with the best max index updated to the current index. + // Note that it is not necessary to also check if the current value is + // less than the best min - the min and max start at the same value, and + // the min can never go above the max after that. This is an + // optimization that saves a nontrivial amount of time. + values[index] > values[bestMax] ? + _minMax(values, valueCount, specialIndices, specialIndexCount, + badValue, index + 1, bestMin, index) : + // Otherwise, if the current value is not higher than the min, continue + // at the next index. If the current value is less than the best min so + // far, then do update the best min for the recursive call. + _minMax(values, valueCount, specialIndices, specialIndexCount, + badValue, index + 1, + values[index] < values[bestMin] ? index : bestMin, + bestMax); +} + +/// Compile-time function that finds the "size" of the enum names and values +/// arrays. The size is the number of constants that would be returned when +/// iterating over the enum. Constants are returned when they are not special +/// (`_bad`, `_def`, `_min`, or `_max`), not bad (not equal to `_bad` if `_bad` +/// is defined, or not the last non-special constant otherwise), not less than +/// the minimum constant, and not less than the maximum constant. +/// +/// Call as `_size(values, count, special, specialCount, bad, min, max)`. +/// +/// @tparam Underlying enum type. +/// @param values Enum values. +/// @param valueCount Size of the `values` array. +/// @param specialIndices Indices of the special constants. +/// @param specialIndexCount Number of special indices. +/// @param badValue The bad value. +/// @param min Minimum value. +/// @param max Maximum value. +/// @param index Current index in the scan over `values`. +/// @param accumulator Number of valid constants found so far. +template +constexpr size_t _size(const UnderlyingType *values, size_t valueCount, + const size_t *specialIndices, size_t specialIndexCount, + UnderlyingType badValue, UnderlyingType min, + UnderlyingType max, size_t index = 0, + size_t accumulator = 0) +{ + return + // If the index has reached the end of values, return the number of + // valid constants found. + index == valueCount ? accumulator : + // If the current index is special, or the value is bad, or the value is + // below the min or above the max, continue scanning at the next index + // without changing the accumulator. + _isSpecial(specialIndices, specialIndexCount, index) || + values[index] == badValue || values[index] < min || + values[index] > max ? + _size(values, valueCount, specialIndices, specialIndexCount, + badValue, min, max, index + 1, accumulator) : + // If the current index is none of the above, continue at the next index + // and increment the accumulator to account for the current value. + _size(values, valueCount, specialIndices, specialIndexCount, + badValue, min, max, index + 1, accumulator + 1); +} + +} // namespace _range + +} // namespace _enum + +// TODO Document reliance on the order of strings and constants being the same. +// TODO Document naming convention: raw, blank, processed. +// TODO Note that the static_assert for _rawSize > 0 never really gets a chance +// to fail in practice, because the preprocessor macros break before that. +// TODO Argue why there is always a first regular and a last regular. +// TODO Document clang WAR for min and max. +// TODO Default should be the first index that is not the invalid index. +// TODO static asserts about the underlying type being an integral type. Allow +// only the types supported by C++11 enum class. + +#define _ENUM_CONSTANT_RESOLVES_FORWARD(EnumType, ConstantIndex, ConstantName) \ + static_assert(ConstantIndex == _ENUM_NOT_FOUND || \ + _enum::_resolveForward(_values, _rawSize, _specialIndices, \ + _ENUM_SPECIAL_COUNT, \ + _values[ConstantIndex]) \ + != _ENUM_NOT_FOUND, \ + "special constant " ConstantName " must be equal to another "\ + "constant"); + +#define _ENUM_CONSTANT_RESOLVES_REVERSE(EnumType, ConstantIndex, ConstantName) \ + static_assert(ConstantIndex == _ENUM_NOT_FOUND || \ + _enum::_resolveReverse(_values, _specialIndices, \ + _ENUM_SPECIAL_COUNT, \ + _values[ConstantIndex], _rawSize - 1) \ + != _ENUM_NOT_FOUND, \ + "special constant " ConstantName " must be equal to another "\ + "constant"); + +namespace _enum { + +// TODO Consider reserving memory statically. This will probably entail a great +// compile-time slowdown, however. +static const char * const* _processNames(const char * const *rawNames, + size_t count) +{ + // Allocate the replacement names array. + const char **processedNames = new const char*[count]; + if (processedNames == nullptr) + return nullptr; + + // Count the number of bytes needed in the replacement names array (an upper + // bound). + size_t bytesNeeded = 0; + for (size_t index = 0; index < count; ++index) + bytesNeeded += std::strlen(rawNames[index]) + 1; + + // Allocate memory for the string data. + char *nameStorage = new char[bytesNeeded]; + if (nameStorage == nullptr) { + delete[] processedNames; + return nullptr; + } + + // Trim each name and place the result in storage, then save a pointer to + // it. + char *writePointer = nameStorage; + for (size_t index = 0; index < count; ++index) { + const char *nameEnd = + std::strpbrk(rawNames[index], _ENUM_NAME_ENDERS); + + size_t symbolCount = + nameEnd == nullptr ? + std::strlen(rawNames[index]) : + nameEnd - rawNames[index]; + + std::strncpy(writePointer, rawNames[index], symbolCount); + processedNames[index] = writePointer; + writePointer += symbolCount; + + *writePointer = '\0'; + ++writePointer; + } + + return processedNames; +} + +template class _GeneratedArrays; + +#define _ENUM_ARRAYS(EnumType, UnderlyingType, ...) \ + class EnumType; \ + \ + namespace _enum { \ + \ + template <> \ + class _GeneratedArrays { \ + public: \ + enum _Value { __VA_ARGS__ }; \ + \ + using Underlying = UnderlyingType; \ + \ + protected: \ + static constexpr Underlying _values[] = \ + { _ENUM_EAT_ASSIGN(UnderlyingType, __VA_ARGS__) }; \ + \ + static constexpr const char *_names[] = \ + { _ENUM_STRINGIZE(__VA_ARGS__) }; \ + \ + static constexpr size_t _rawSize = \ + _ENUM_PP_COUNT(__VA_ARGS__); \ + }; \ + \ + constexpr _GeneratedArrays::Underlying _ENUM_WEAK \ + _GeneratedArrays::_values[]; \ + \ + constexpr const char * _ENUM_WEAK _GeneratedArrays::_names[]; \ + \ + \ + template <> \ + const char * const * _ENUM_WEAK _Internal::_processedNames = \ + nullptr; \ + \ + } + +// TODO Compute first index for iteration while computing range properties. + +template +class _Internal : public _GeneratedArrays { + protected: + using _arrays = _GeneratedArrays; + using _arrays::_values; + using _arrays::_names; + using _arrays::_rawSize; + + public: + using typename _arrays::_Value; + using typename _arrays::Underlying; + + protected: + static_assert(_rawSize > 0, "no constants defined in enum type"); + + static constexpr _enum::_special_names::_Indices + _indices = + _enum::_special_names::_find(_names, _rawSize - 1); + + static constexpr size_t _specialIndices[] = + { _indices.bad, _indices.def, _indices.min, _indices.max }; + + _ENUM_CONSTANT_RESOLVES_REVERSE(EnumType, _indices.bad, _ENUM_BAD); + _ENUM_CONSTANT_RESOLVES_FORWARD(EnumType, _indices.def, _ENUM_DEF); + _ENUM_CONSTANT_RESOLVES_FORWARD(EnumType, _indices.min, _ENUM_MIN); + _ENUM_CONSTANT_RESOLVES_REVERSE(EnumType, _indices.max, _ENUM_MAX); + + static constexpr size_t _badIndex = + _indices.bad == _ENUM_NOT_FOUND ? + _enum::_highestRegular(_specialIndices, _ENUM_SPECIAL_COUNT, + _rawSize - 1) : + _indices.bad; + + static_assert(_badIndex != _ENUM_NOT_FOUND, + "_bad not defined and no regular constants in enum type"); + + static constexpr size_t _lowestValidIndex = + _enum::_lowestValid(_values, _rawSize, _specialIndices, + _ENUM_SPECIAL_COUNT, _values[_badIndex]); + + static constexpr size_t _highestValidIndex = + _enum::_highestValid(_values, _specialIndices, _ENUM_SPECIAL_COUNT, + _values[_badIndex], _rawSize - 1); + + static_assert(_lowestValidIndex != _ENUM_NOT_FOUND, + "no valid (non-bad) constants in enum type"); + static_assert(_highestValidIndex != _ENUM_NOT_FOUND, + "no valid (non-bad) constants in enum type"); + + static constexpr size_t _defIndex = + _indices.def == _ENUM_NOT_FOUND ? _lowestValidIndex : _indices.def; + + static constexpr _enum::_range::_MinMax + _minMax = + _enum::_range::_minMax(_values, _rawSize, _specialIndices, + _ENUM_SPECIAL_COUNT, _values[_badIndex], + _lowestValidIndex + 1, _lowestValidIndex, + _lowestValidIndex); + + static constexpr size_t _minIndex = + _indices.min == _ENUM_NOT_FOUND ? _minMax.min : _indices.min; + + static constexpr size_t _maxIndex = + _indices.max == _ENUM_NOT_FOUND ? _minMax.max : _indices.max; + + static_assert(_values[_minIndex] <= _values[_maxIndex], + "minimum constant has value greater than maximum constant"); + + static constexpr size_t _size = + _enum::_range::_size(_values, _rawSize, _specialIndices, + _ENUM_SPECIAL_COUNT, _values[_badIndex], + _values[_minIndex], _values[_maxIndex]); + + static constexpr size_t _specialBadIndex = _indices.bad; + static constexpr size_t _specialDefIndex = _indices.def; + static constexpr size_t _specialMinIndex = _indices.min; + static constexpr size_t _specialMaxIndex = _indices.max; + + static constexpr bool _isSpecialIndex(size_t index) + { + return + index == _specialBadIndex ? true : + index == _specialDefIndex ? true : + index == _specialMinIndex ? true : + index == _specialMaxIndex ? true : + false; + } + +// Clang complains about the comparison with "min" when the underlying type is +// unsigned and "min" is 0. Disable that warning. GCC doesn't even have this +// warning under this name (and does not complain). +#ifdef __clang__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wtautological-compare" +#endif // #ifdef __clang__ + + static constexpr bool _isIterableIndex(size_t index) + { + return + _isSpecialIndex(index) ? false : + _values[index] == _values[_badIndex] ? false : + _values[index] < _values[_minIndex] ? false : + _values[index] > _values[_maxIndex] ? false : + true; + } + +#ifdef __clang__ +#pragma GCC diagnostic pop +#endif // #ifdef __clang__ + + static const char * const *_processedNames; + + static void _processNames() + { + if (_processedNames == nullptr) + _processedNames = _enum::_processNames(_names, _rawSize); + } + + using ValueIterable = + _Iterable; + using NameIterable = + _Iterable; + + friend ValueIterable; + friend NameIterable; + + static ValueIterable values() + { + return ValueIterable(_values, false); + } + + static ValueIterable allValues() + { + return ValueIterable(_values, true); + } + + static NameIterable names() + { + _processNames(); + + return NameIterable(_processedNames, false); + } + + static NameIterable allNames() + { + _processNames(); + + return NameIterable(_processedNames, true); + } + + static const char* desc(EnumType value) + { + _processNames(); + + for (size_t index = 0; index < _rawSize; ++index) { + if (_values[index] == value) + return _processedNames[index]; + } + + return _processedNames[_badIndex]; + } + + static const char* descE(EnumType value) + { + const char *result = desc(value); + + // Note that this is a pointer comparison. Takes deliberate advantage of + // the fact that exactly this pointer is returned by desc() in case of + // failure. + if (result == _processedNames[_badIndex]) { + // TODO Throw an exception here. + } + else + return result; + } + + static EnumType find(const char *name) + { + _processNames(); + + for (size_t index = 0; index < _rawSize; ++index) { + if (strcmp(_processedNames[index], name) == 0) + return (EnumType)_values[index]; + } + + return (EnumType)_values[_badIndex]; + } + + static EnumType findE(const char *name) + { + EnumType result = find(name); + + if (result == (_Value)_values[_badIndex]) + // TODO Throw an exception here. + else + return result; + } + + static EnumType caseFind(const char *name) + { + _processNames(); + + for (size_t index = 0; index < _rawSize; ++index) { + if (strcasecmp(_processedNames[index], name) == 0) + return (EnumType)_values[index]; + } + + return (EnumType)_values[_badIndex]; + } + + static EnumType caseFindE(const char *name) + { + EnumType result = caseFind(name); + + if (result == (_Value)_values[_badIndex]) { + // TODO Throw an exception here. + } + else + return result; + } + +// See comment by _isIterableIndex. +#ifdef __clang__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wtautological-compare" +#endif // #ifdef __clang__ + + template + static bool valid(IntegralType value) + { + static_assert(is_integral::value, + "argument to EnumType::valid must have integral type"); + static_assert(is_signed::value == + is_signed::value, + "argument to EnumType::valid must be signed if and only " + "if underlying type of EnumType is signed"); + + return value >= _values[_minIndex] && + value <= _values[_maxIndex] && + value != _values[_badIndex]; + } + +#ifdef __clang__ +#pragma GCC diagnostic pop +#endif // #ifdef __clang__ + + static bool valid(const char *name) + { + EnumType value = find(name); + + return valid(value.toUnderlying()); + } + + static bool caseValid(const char *name) + { + EnumType value = caseFind(name); + + return valid(value.toUnderlying()); + } + + public: + bool operator ==(const EnumType &other) const + { return static_cast(*this)._value == other._value; } + bool operator ==(const _Value value) const + { return static_cast(*this)._value == value; } + template bool operator ==(T other) const = delete; + + bool operator !=(const EnumType &other) const + { return !(*this == other); } + bool operator !=(const _Value value) const + { return !(*this == value); } + template bool operator !=(T other) const = delete; + + bool operator <(const EnumType &other) const + { return static_cast(*this)._value < other._value; } + bool operator <(const _Value value) const + { return static_cast(*this)._value < value; } + template bool operator <(T other) const = delete; + + bool operator <=(const EnumType &other) const + { return static_cast(*this)._value <= other._value; } + bool operator <=(const _Value value) const + { return static_cast(*this)._value <= value; } + template bool operator <=(T other) const = delete; + + bool operator >(const EnumType &other) const + { return static_cast(*this)._value > other._value; } + bool operator >(const _Value value) const + { return static_cast(*this)._value > value; } + template bool operator >(T other) const = delete; + + bool operator >=(const EnumType &other) const + { return static_cast(*this)._value >= other._value; } + bool operator >=(const _Value value) const + { return static_cast(*this)._value >= value; } + template bool operator >=(T other) const = delete; + + int operator -() const = delete; + template int operator +(T other) const = delete; + template int operator -(T other) const = delete; + template int operator *(T other) const = delete; + template int operator /(T other) const = delete; + template int operator %(T other) const = delete; + + template int operator <<(T other) const = delete; + template int operator >>(T other) const = delete; + + int operator ~() const = delete; + template int operator &(T other) const = delete; + template int operator |(T other) const = delete; + template int operator ^(T other) const = delete; + + int operator !() const = delete; + template int operator &&(T other) const = delete; + template int operator ||(T other) const = delete; +}; + +} diff --git a/pp_map_gen.py b/pp_map_gen.py new file mode 100755 index 0000000..ae9cbec --- /dev/null +++ b/pp_map_gen.py @@ -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)