mirror of
https://github.com/aantron/better-enums.git
synced 2025-12-06 16:56:42 +08:00
Compare commits
No commits in common. "master" and "0.9.0" have entirely different histories.
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*.h linguist-language=C++
|
||||
*.tmpl linguist-language=HTML
|
||||
1
.github/FUNDING.yml
vendored
1
.github/FUNDING.yml
vendored
@ -1 +0,0 @@
|
||||
github: aantron
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@ -5,4 +5,4 @@ scratch/
|
||||
doc/html/
|
||||
doc-publish/
|
||||
test/cxxtest/*.cc
|
||||
test/build
|
||||
test/platform/
|
||||
|
||||
38
.travis.yml
38
.travis.yml
@ -1,38 +0,0 @@
|
||||
language: cpp
|
||||
|
||||
env:
|
||||
- COMPILER="clang++-3.7"
|
||||
- COMPILER="g++-5"
|
||||
- COMPILER="g++-4.6"
|
||||
- COMPILER="g++-4.7"
|
||||
- COMPILER="g++-4.4"
|
||||
- COMPILER="g++-4.8"
|
||||
- COMPILER="g++-4.9"
|
||||
- COMPILER="clang++-3.3"
|
||||
- COMPILER="clang++-3.4"
|
||||
- COMPILER="clang++-3.5"
|
||||
- COMPILER="clang++-3.6"
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- env: COMPILER="clang++-3.3"
|
||||
- env: COMPILER="clang++-3.5"
|
||||
|
||||
before_script:
|
||||
- sudo add-apt-repository --yes ppa:ubuntu-toolchain-r/test
|
||||
- sudo add-apt-repository --yes ppa:h-rayflood/llvm
|
||||
- sudo add-apt-repository -y 'deb http://llvm.org/apt/precise/ llvm-toolchain-precise-3.5 main'
|
||||
- sudo add-apt-repository -y 'deb http://llvm.org/apt/precise/ llvm-toolchain-precise-3.6 main'
|
||||
- sudo add-apt-repository -y 'deb http://llvm.org/apt/precise/ llvm-toolchain-precise-3.7 main'
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install --allow-unauthenticated $COMPILER
|
||||
- git clone https://github.com/CxxTest/cxxtest.git cxxtest-ro
|
||||
- curl -O https://cmake.org/files/v3.2/cmake-3.2.3-Linux-x86_64.tar.gz
|
||||
- tar -xzf cmake-3.2.3-Linux-x86_64.tar.gz
|
||||
- sudo cp -fR cmake-3.2.3-Linux-x86_64/* /usr
|
||||
|
||||
script:
|
||||
- export PATH="$PATH:$(pwd)/cxxtest-ro/bin"
|
||||
- ln -s cxxtest-ro/cxxtest cxxtest
|
||||
- cd test
|
||||
- make COMPILER=$COMPILER unix
|
||||
@ -1,4 +1,4 @@
|
||||
Copyright (c) 2012-2024, Anton Bachin
|
||||
Copyright (c) 2012-2015, Anton Bachin
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
119
README.md
119
README.md
@ -1,21 +1,39 @@
|
||||
# Better Enums [![Try online][wandbox-img]][wandbox] [![Travis status][travis-img]][travis] [![AppVeyor status][appveyor-img]][appveyor]
|
||||
# Better Enums
|
||||
|
||||
[wandbox]: http://melpon.org/wandbox/permlink/2QCi3cwQnplAToge
|
||||
[wandbox-img]: https://img.shields.io/badge/try%20it-online-blue.svg
|
||||
[appveyor]: https://ci.appveyor.com/project/aantron/better-enums/branch/master
|
||||
[travis]: https://travis-ci.org/aantron/better-enums/branches
|
||||
[travis-img]: https://img.shields.io/travis/aantron/better-enums/master.svg?label=travis
|
||||
[appveyor-img]: https://img.shields.io/appveyor/ci/aantron/better-enums/master.svg?label=appveyor
|
||||
[license-img]: https://img.shields.io/badge/license-BSD-lightgrey.svg
|
||||
Reflective compile-time C++ enum library with clean syntax, in a single header
|
||||
file. For example:
|
||||
|
||||
Reflective compile-time enum library with clean syntax, in a single header
|
||||
file, and without dependencies.
|
||||
#include <enum.h>
|
||||
ENUM(Channel, int, Red = 1, Green, Blue)
|
||||
|
||||
![Better Enums code overview][sample]
|
||||
defines a type `Channel`. You can then do natural things such as:
|
||||
|
||||
[sample]: https://raw.githubusercontent.com/aantron/better-enums/master/doc/image/sample.gif
|
||||
```cpp
|
||||
Channel channel = Channel::Green;
|
||||
|
||||
In C++11, *everything* can be used at compile time. You can convert your enums,
|
||||
channel._to_string(); // Results in the string "Green"
|
||||
Channel::_from_string("Red"); // Results in Channel::Red
|
||||
|
||||
Channel::_from_integral(3); // Checked cast, Channel::Blue
|
||||
|
||||
Channel::_size; // Number of channels (3)
|
||||
Channel::_values()[0]; // Get the first channel
|
||||
|
||||
for (Channel channel : Channel::_values()) {
|
||||
process(channel); // Iterate over all channels
|
||||
}
|
||||
|
||||
// Natural switch, compiler checks the cases
|
||||
switch (channel) {
|
||||
case Channel::Red: break;
|
||||
case Channel::Green: break;
|
||||
case Channel::Blue: break;
|
||||
}
|
||||
```
|
||||
|
||||
...and more.
|
||||
|
||||
In C++11, *everything* is available at compile time. You can convert your enums,
|
||||
loop over them, [find their max][max],
|
||||
[statically enforce conventions][enforce], and pass along the results as
|
||||
template arguments or to `constexpr` functions. All the reflection is available
|
||||
@ -31,73 +49,36 @@ See the [project page][project] for full documentation.
|
||||
[enforce]: http://aantron.github.io/better-enums/demo/SpecialValues.html
|
||||
[project]: http://aantron.github.io/better-enums
|
||||
|
||||
<br/>
|
||||
|
||||
## Installation
|
||||
|
||||
Simply add `enum.h` to your project.
|
||||
Simply add `enum.h` to your project — that's it.
|
||||
|
||||
<br/>
|
||||
Then, include it and use the `ENUM` macro. Your compiler will generate the rich
|
||||
enums that are missing from standard C++.
|
||||
|
||||
## Additional features
|
||||
|
||||
- Uses only standard C++, though, for C++98, variadic macro support is required
|
||||
(major compilers have it).
|
||||
- Supported and tested on [clang, gcc, and msvc][testing].
|
||||
- No dependencies and no external build tools. Uses only standard C++, though,
|
||||
for C++98, variadic macro support is required.
|
||||
- Supported and tested on clang, gcc, and msvc.
|
||||
- Fast compilation. You have to declare a few dozen enums to slow down your
|
||||
compiler as much as [only including `iostream` does][performance].
|
||||
- Use any initializers and sparse ranges, just like with a built-in enum.
|
||||
- Control over size and alignment — you choose the representation type.
|
||||
- Stream operators.
|
||||
- Does not use the heap and can be compiled with exceptions disabled, for use in
|
||||
minimal freestanding environments.
|
||||
compiler as much as [just including `iostream` does][performance].
|
||||
- Use any initializers, just like with a built-in enum.
|
||||
- Guaranteed size and alignment — you choose the representation type.
|
||||
|
||||
[testing]: http://aantron.github.io/better-enums/CompilerSupport.html
|
||||
[performance]: http://aantron.github.io/better-enums/Performance.html
|
||||
|
||||
<br/>
|
||||
## Contact
|
||||
|
||||
## Limitations
|
||||
Don't hesitate to contact me about features or bugs:
|
||||
[antonbachin@yahoo.com](mailto:antonbachin@yahoo.com), or open an issue on
|
||||
GitHub.
|
||||
|
||||
1. The biggest limitation is that the `BETTER_ENUM` macro can't be used inside a
|
||||
class. This seems [difficult to remove][nested]. There is a workaround with
|
||||
`typedef` (or C++11 `using`):
|
||||
## License and history
|
||||
|
||||
```c++
|
||||
BETTER_ENUM(SomePrefix_Color, uint8_t, Red, Green, Blue)
|
||||
Better Enums is released under the BSD 2-clause license. See
|
||||
[LICENSE](https://github.com/aantron/better-enums/blob/master/LICENSE).
|
||||
|
||||
struct triplet {
|
||||
typedef SomePrefix_Color Color;
|
||||
Color r, g, b;
|
||||
};
|
||||
|
||||
triplet::Color color;
|
||||
```
|
||||
|
||||
You can, however, use `BETTER_ENUM` inside a namespace.
|
||||
|
||||
2. The macro has a soft limit of 64 declared constants. You can extend it by
|
||||
following [these instructions][extend]. Ultimately, the number of constants is
|
||||
limited by your compiler's maximum macro argument count.
|
||||
|
||||
3. In some cases, it is necessary to prefix constants such as `Channel::Red` with a
|
||||
`+` to explicitly promote them to type `Channel`. For example, if you are doing
|
||||
a comparison:
|
||||
|
||||
```c++
|
||||
channel == +Channel::Red
|
||||
```
|
||||
|
||||
4. On msvc, you may need to enable [warning C4062][C4062] to get `switch` case exhaustiveness checking.
|
||||
|
||||
[nested]: http://aantron.github.io/better-enums/DesignDecisionsFAQ.html#NoEnumInsideClass
|
||||
[extend]: http://aantron.github.io/better-enums/ExtendingLimits.html
|
||||
[C4062]: https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-4-c4062
|
||||
|
||||
<br/>
|
||||
|
||||
## History
|
||||
|
||||
The original version of the library was developed by the author in the winter of
|
||||
2012-2013 at Hudson River Trading, as a replacement for an older generator
|
||||
called `BETTER_ENUM`.
|
||||
The library was originally developed by the author in the winter of 2012-2013 at
|
||||
Hudson River Trading, as a replacement for an older generator called
|
||||
`BETTER_ENUM`.
|
||||
|
||||
29
appveyor.yml
29
appveyor.yml
@ -1,29 +0,0 @@
|
||||
version: "{build}"
|
||||
|
||||
branches:
|
||||
except:
|
||||
- gh-pages
|
||||
- traits
|
||||
|
||||
skip_tags : true
|
||||
shallow_clone: true
|
||||
|
||||
os: Visual Studio 2017
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- TITLE: vc2017
|
||||
COMPILER: Visual Studio 15 2017
|
||||
- TITLE: vc2015
|
||||
COMPILER: Visual Studio 14 2015
|
||||
- TITLE: vc2013
|
||||
COMPILER: Visual Studio 12 2013
|
||||
|
||||
install:
|
||||
- git clone --depth 1 https://github.com/CxxTest/cxxtest.git
|
||||
|
||||
build_script:
|
||||
- set CL=/I C:\projects\better-enums\cxxtest
|
||||
- set PATH=%PATH%;C:\projects\better-enums\cxxtest\bin;C:\cygwin\bin
|
||||
- cd test
|
||||
- make ms
|
||||
@ -7,7 +7,7 @@ $internal_toc
|
||||
The declaration
|
||||
|
||||
#include <enum.h>
|
||||
<em>BETTER_ENUM</em>(<em>Enum</em>, <em>underlying_type</em>, <em>A</em>, <em>B</em>, <em>C</em>, ...)
|
||||
<em>ENUM</em>(<em>Enum</em>, <em>underlying_type</em>, <em>A</em>, <em>B</em>, <em>C</em>, ...)
|
||||
|
||||
generates a new class type `Enum` which is notionally similar to the type
|
||||
created by this $cxx11 declaration:
|
||||
@ -20,29 +20,29 @@ That is, `Enum` is a scoped enumerated type with constants `Enum::A`, `Enum::B`,
|
||||
`Enum::C`, and so on, with memory representation the same as `underlying_type`.
|
||||
It is possible to supply initializers for any of the constants:
|
||||
|
||||
<em>BETTER_ENUM</em>(Enum, underlying_type, <em>A</em> = <em>1</em>, <em>B</em> = <em>constant_expression</em>, <em>C</em> = <em>A</em>, ...)
|
||||
<em>ENUM</em>(Enum, underlying_type, <em>A</em> = <em>1</em>, <em>B</em> = <em>constant_expression</em>, <em>C</em> = <em>A</em>, ...)
|
||||
|
||||
The initializers have the same meaning and constraints as in a built-in `enum`
|
||||
or `enum class` declaration.
|
||||
|
||||
---
|
||||
|
||||
The principal differences between the types declared by the `BETTER_ENUM` macro
|
||||
and `enum class` are:
|
||||
The principal differences between the types declared by the `ENUM` macro and
|
||||
`enum class` are:
|
||||
|
||||
- `BETTER_ENUM` is available for $cxx98
|
||||
- `ENUM` is available for $cxx98
|
||||
[compilers](${prefix}CompilerSupport.html) supporting `__VA_ARGS__` —
|
||||
all major compilers — while `enum class` is restricted to $cxx11,
|
||||
- the `BETTER_ENUM` type is implicitly convertible to integral types, though
|
||||
this can be [disabled](${prefix}OptInFeatures.html#StrictConversions) when
|
||||
using $cxx11, and
|
||||
- the `BETTER_ENUM` type supports a set of reflective operations, detailed in
|
||||
the rest of this reference.
|
||||
- the `ENUM` type is implicitly convertible to integral types, though this can
|
||||
be [disabled](${prefix}OptInFeatures.html#StrictConversions) when using
|
||||
$cxx11, and
|
||||
- the `ENUM` type supports a set of reflective operations, detailed in the
|
||||
rest of this reference.
|
||||
|
||||
---
|
||||
|
||||
The types produced by the `BETTER_ENUM` macro are called *Better Enums* in the
|
||||
rest of this reference.
|
||||
The types produced by the `ENUM` macro are called *Better Enums* in the rest of
|
||||
this reference.
|
||||
|
||||
Better Enums are similar to their underlying type for the purposes of argument
|
||||
passing. This means that they typically fit into a machine word, and should be
|
||||
@ -57,7 +57,7 @@ in order to avoid conflicts with potential constant names.
|
||||
|
||||
The rest of this reference uses the following declaration as a running example:
|
||||
|
||||
<em>BETTER_ENUM</em>(<em>Enum</em>, <em>int</em>, <em>A</em>, <em>B</em>, <em>C</em>)
|
||||
<em>ENUM</em>(<em>Enum</em>, <em>int</em>, <em>A</em>, <em>B</em>, <em>C</em>)
|
||||
|
||||
|
||||
|
||||
@ -69,8 +69,8 @@ rest of the documentation.
|
||||
|
||||
#### <em>typedef _enumerated</em>
|
||||
|
||||
An internal type used to declare constants. The `BETTER_ENUM` macro generates
|
||||
something similar to
|
||||
An internal type used to declare constants. The `ENUM` macro generates something
|
||||
similar to
|
||||
|
||||
~~~comment
|
||||
<em>struct Enum</em> {
|
||||
@ -150,14 +150,9 @@ using <em>optional</em> = <em>better_enums::optional</em><<em>Enum</em>>;
|
||||
The types and members described here have to do with the sequence of constants
|
||||
declared, i.e. `A`, `B`, `C` in the [running example](#RunningExample).
|
||||
|
||||
#### static constexpr size_t <em>_size</em>()
|
||||
#### static constexpr size_t <em>_size</em>
|
||||
|
||||
The number of constants declared. `Enum::_size() == 3`.
|
||||
|
||||
#### static constexpr const size_t <em>_size_constant</em>
|
||||
|
||||
Same as [`_size`](#_size), but a constant instead of a function. This is
|
||||
provided for use in $cxx98 constant expressions.
|
||||
The number of constants declared. `Enum::_size == 3`.
|
||||
|
||||
#### <em>typedef _value_iterable</em>
|
||||
|
||||
@ -228,7 +223,7 @@ If the given string is the exact name of a declared constant, returns the
|
||||
constant. Otherwise, throws `std::runtime_error`. Running time is linear in the
|
||||
number of declared constants multiplied by the length of the longest constant.
|
||||
|
||||
#### static constexpr optional<Enum> <em>_from_string_nothrow</em>(const char*)
|
||||
#### static constexpr optional<Enum> <em>_from_string_nothrow</em>(const char*)
|
||||
|
||||
Same as [`_from_string`](#_from_string), but does not throw an exception on
|
||||
failure. Returns an [optional value](#StructBetter_enumsoptional) instead.
|
||||
@ -238,7 +233,7 @@ failure. Returns an [optional value](#StructBetter_enumsoptional) instead.
|
||||
Same as [`_from_string`](#_from_string), but comparison is up to case, in the
|
||||
usual sense in the Latin-1 encoding.
|
||||
|
||||
#### static constexpr optional<Enum> <em>_from_string_nocase_nothrow</em>(const char*)
|
||||
#### static constexpr optional<Enum> <em>_from_string_nocase_nothrow</em>(const char*)
|
||||
|
||||
Is to [`_from_string_nocase`](#_from_string_nocase) as
|
||||
[`_from_string_nothrow`](#_from_string_nothrow) is to
|
||||
@ -260,7 +255,7 @@ case as in [`_from_string_nocase`](#_from_string_nocase).
|
||||
Evaluates to the name of the Better Enum type. `Enum::_name()` is the same
|
||||
string as `"Enum"`.
|
||||
|
||||
#### <em>typedef _name_iterable</em>
|
||||
#### typedef <em>_name_iterable</em>
|
||||
|
||||
Type of object that permits iteration over names of declared constants. Has at
|
||||
least `constexpr` `begin()`, `end()`, and `size()` methods. `operator[]` is also
|
||||
@ -268,7 +263,7 @@ available, but is `constexpr` if and only if [`_to_string`](#_to_string) is
|
||||
`constexpr`. Iteration visits constants in order of declaration. See usage
|
||||
example under [`_names`](#_names).
|
||||
|
||||
#### <em>typedef _name_iterator</em>
|
||||
#### typedef <em>_name_iterator</em>
|
||||
|
||||
Random-access iterator type for `_name_iterable`. Most operations are
|
||||
`constexpr`, but dereferencing is `constexpr` if and only if
|
||||
@ -327,7 +322,7 @@ example,
|
||||
(+<em>Enum::C</em>)<em>._to_integral</em>() == <em>2</em>
|
||||
|
||||
Note that Better Enums are already implicitly convertible to their underlying
|
||||
integral types [by default](${prefix}OptInFeatures.html#StrictConversions).
|
||||
integral types [by default](${prefix}OptInFeatures.html#StrictConversion).
|
||||
You may still want to use this function, however, for clarity, and to ensure
|
||||
that your code remains compatible if the strict conversions feature is enabled
|
||||
later.
|
||||
@ -342,7 +337,7 @@ of one of the declared constants.
|
||||
<em>Enum::_from_integral</em>(<em>2</em>); // Enum::C
|
||||
<em>Enum::_from_integral</em>(<em>42</em>); // std::runtime_error
|
||||
|
||||
#### static constexpr optional<Enum> <em>_from_integral_nothrow</em>(_integral)
|
||||
#### static constexpr optional<Enum> <em>_from_integral_nothrow</em>(_integral)
|
||||
|
||||
Checked conversion as [`_from_integral`](#_from_integral), but does not throw an
|
||||
exception on failure. Returns an [optional value](#StructBetter_enumsoptional)
|
||||
@ -370,64 +365,6 @@ constants.
|
||||
|
||||
|
||||
|
||||
### Index lookup
|
||||
|
||||
#### member constexpr std::size_t <em>_to_index</em>() const
|
||||
|
||||
Returns the index of a Better Enum value within its enum declaration. The index
|
||||
is determined from the value only; if two constants in the declaration have the
|
||||
same value, this function may return the index of either constant.
|
||||
|
||||
If the value does not correspond to any constant in the declaration (for
|
||||
example, if it was obtained using an unchecked conversion or a cast), then the
|
||||
behavior of `value._to_index` is undefined.
|
||||
|
||||
#### static constexpr Enum <em>_from_index</em>(size_t)
|
||||
|
||||
Returns the value of the constant with the given index. Throws
|
||||
`std::runtime_error` if not given the index of one of the constants.
|
||||
|
||||
#### static constexpr Enum <em>_from_index_unchecked</em>(size_t)
|
||||
|
||||
Returns the value of the constant with the given index. If not given one of the
|
||||
constants in the declaration of the enum, the returned value is undefined.
|
||||
|
||||
#### static constexpr optional<Enum> <em>_from_index_nothrow</em>(size_t)
|
||||
|
||||
Returns the value of the constant with the given index.
|
||||
|
||||
|
||||
|
||||
### Stream operators
|
||||
|
||||
#### non-member std::ostream& <em>operator <<</em>(std::ostream&, const Enum&)
|
||||
|
||||
Formats the given enum to the given stream in the same way as
|
||||
[`_to_string`](#_to_string).
|
||||
|
||||
#### non-member std::istream& <em>operator >></em>(std::istream&, Enum&)
|
||||
|
||||
Reads from the given stream and attempts to parse an enum value in the same way
|
||||
as [`_from_string`](#_from_string). In case of failure, sets the stream's
|
||||
`failbit`.
|
||||
|
||||
|
||||
|
||||
### Hashing
|
||||
|
||||
#### macro <em>BETTER_ENUMS_DECLARE_STD_HASH</em>(Enum)
|
||||
|
||||
Use this outside namespace scope to declare a specialization of `std::hash` for
|
||||
the type `Enum`. For example:
|
||||
|
||||
// This declaration might be inside a namespace.
|
||||
<em>BETTER_ENUM</em>(<em>Channel</em>, int, Red, Green, Blue)
|
||||
|
||||
// Later, outside the namespace:
|
||||
<em>BETTER_ENUMS_DECLARE_STD_HASH</em>(<em>Channel</em>)
|
||||
|
||||
|
||||
|
||||
%% class = api
|
||||
|
||||
%% description = Detailed description of the Better Enums API.
|
||||
|
||||
@ -1,94 +0,0 @@
|
||||
# Contributing to Better Enums
|
||||
|
||||
All contributions are welcome: feedback, documentation changes, and, of course,
|
||||
pull requests and patch suggestions. A list of contributors is maintained in the
|
||||
`CONTRIBUTORS` file. I am grateful to everyone mentioned.
|
||||
|
||||
## Some major outstanding issues
|
||||
|
||||
- Better Enums currently uses linear scans for lookup, so it could really
|
||||
benefit from a lookup data structure that is really fast to generate at
|
||||
compile time. All the sorts and other approaches I have tried so far,
|
||||
including MPL, Meta, and my own, have been 10-50 times too slow for practical
|
||||
use.
|
||||
- Alternatively, if there is a method to detect whether a given function is
|
||||
running at compile or run time, Better Enums could use linear scans during
|
||||
compilation, then do a sort at program initialization, and then use fast
|
||||
lookups.
|
||||
- It would be nice if name trimming was always `constexpr`. Right now, this is
|
||||
not the default, because it makes compilation of each Better Enum about four
|
||||
times slower. Better Enums needs a fast way to take a `const char*`, chop off
|
||||
any initializers, and return the new `const char*`.
|
||||
- I would like to enable more warning flags besides just
|
||||
`-Wall -Wextra -pedantic`, but CxxTest triggers the extra warnings.
|
||||
`CMakeLists.txt` should probably be modified to add the extra warnings to all
|
||||
targets that are not CxxTest tests.
|
||||
|
||||
## Testing
|
||||
|
||||
I typically write small programs to play around with `enum.h`. The `scratch/`
|
||||
directory is in `.gitignore` for this purpose. Create `scratch/` and feel free
|
||||
to do anything you want in it. Once your change is nearly complete, you should
|
||||
run the automated test suite.
|
||||
|
||||
While still actively developing, run `make -C test` to do quick builds. Before
|
||||
submitting your pull request, run `make -C test default-all`. The first command
|
||||
tests your code on your system compiler in one configuration, and the second
|
||||
command tests it in all configurations that your compiler supports.
|
||||
*Configurations* refers to the optional features of Better Enums, such as
|
||||
`constexpr` string conversion and using an `enum class` for `switch` statements.
|
||||
|
||||
Once your pull request is submitted, the [AppVeyor][appveyor] and
|
||||
[Travis][travis] web services will automatically test it on many versions of
|
||||
GCC, Clang, and Visual C++. If you have more than one compiler installed
|
||||
locally, you can run either the `unix` or `ms` target in `test/Makefile` to test
|
||||
on a specific compiler. Open the `Makefile` file and find the targets for
|
||||
instructions.
|
||||
|
||||
If your pull request does not include any changes to the code (for example, you
|
||||
have changed only documentation), add the text `[ci skip]` to the commit message
|
||||
to prevent AppVeyor and Travis from testing the commit.
|
||||
|
||||
The `make` targets mentioned above depend on the following software:
|
||||
|
||||
- Make
|
||||
- CMake
|
||||
- Python 2
|
||||
- [CxxTest][cxxtest]
|
||||
|
||||
CxxTest's `bin/` directory has to be in `PATH` and the root `cxxtest/` directory
|
||||
has to be in whatever environment variable your system compiler uses to search
|
||||
for header files.
|
||||
|
||||
On Windows, you also need [Cygwin][cygwin]. The directory containing
|
||||
`MSBuild.exe` must be in `PATH`.
|
||||
|
||||
The programs in `example/` are generated from the Markdown files in
|
||||
`doc/tutorial/` and `doc/demo/`. If you have edited the Markdown files, you
|
||||
should run `make -C test examples` to update the example program sources.
|
||||
|
||||
If you have created a new example program or compilation performance test, add
|
||||
it to `test/CMakeLists.txt`. Search for the name of an existing program, such as
|
||||
`1-hello-world`, and you should see where to add new ones.
|
||||
|
||||
[cygwin]: https://www.cygwin.com
|
||||
[cxxtest]: http://cxxtest.com
|
||||
[appveyor]: https://ci.appveyor.com/project/aantron/better-enums
|
||||
[travis]: https://travis-ci.org/aantron/better-enums
|
||||
|
||||
## Commits
|
||||
|
||||
Please write descriptive commit messages that follow the 50/72 rule. I am likely
|
||||
to edit commit messages when merging into `master`. I will also squash multiple
|
||||
commits in most cases. If you prefer I not do either one, let me know, but then
|
||||
we will have to go back and forth on the exact contents of the pull request.
|
||||
|
||||
I am maintaining the `master` branch in such a way that every commit passes its
|
||||
tests, i.e. `master` is always stable. Every commit going into `master` is first
|
||||
fully tested in its pull request branch, or in a temporary staging branch, if
|
||||
necessary.
|
||||
|
||||
## Generating the documentation
|
||||
|
||||
To generate an offline copy of the documentation, run `make -C doc`. To view it,
|
||||
open `doc/html/index.html`.
|
||||
@ -1,11 +0,0 @@
|
||||
Here you will find a list of everyone I have to thank for contributing code,
|
||||
suggestions, comments, other feedback, or anything else that was useful to the
|
||||
library. This file never shrinks - if a name goes missing, it's because a chat
|
||||
handle was replaced by a real name. There is no significance to the order.
|
||||
|
||||
Thanks to:
|
||||
|
||||
Tony Van Eerd
|
||||
Ben Alex
|
||||
Simon Stienen
|
||||
Alexander Buddenbrock
|
||||
@ -1,10 +1,11 @@
|
||||
## Compiler support
|
||||
|
||||
Better Enums aims to support all major compilers. It is known to work on:
|
||||
Better Enums aims to support all major compilers. It is known to definitely work
|
||||
on
|
||||
|
||||
- clang 3.3 to 3.9
|
||||
- gcc 4.3 to 5.3
|
||||
- Visual C++ 2008 to 2015.
|
||||
- clang 3.3 to 3.6
|
||||
- gcc 4.3 to 5.1
|
||||
- Visual C++ 2013U4, 2015RC.
|
||||
|
||||
The library can be used with any compiler that supports either $cxx11, or $cxx98
|
||||
with the `__VA_ARGS__` extension. This includes every version of gcc and clang I
|
||||
@ -75,21 +76,6 @@ vc2015 /EHsc
|
||||
vc2015 /EHsc /DBETTER_ENUMS_STRICT_CONVERSION
|
||||
vc2013 /EHsc
|
||||
vc2013 /EHsc /DBETTER_ENUMS_STRICT_CONVERSION
|
||||
vc2012 /EHsc
|
||||
vc2010 /EHsc
|
||||
vc2008 /EHsc
|
||||
clang++39 -std=c++11
|
||||
clang++39 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
|
||||
clang++39 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
|
||||
clang++39 -std=c++98
|
||||
clang++38 -std=c++11
|
||||
clang++38 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
|
||||
clang++38 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
|
||||
clang++38 -std=c++98
|
||||
clang++37 -std=c++11
|
||||
clang++37 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
|
||||
clang++37 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
|
||||
clang++37 -std=c++98
|
||||
clang++36 -std=c++11
|
||||
clang++36 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
|
||||
clang++36 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
|
||||
@ -102,11 +88,14 @@ clang++34 -std=c++11
|
||||
clang++34 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
|
||||
clang++34 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
|
||||
clang++34 -std=c++98
|
||||
clang++33 -std=c++11
|
||||
clang++33 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
|
||||
clang++33 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
|
||||
clang++33 -std=c++98
|
||||
g++53 -std=c++11
|
||||
g++53 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
|
||||
g++53 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
|
||||
g++53 -std=c++98
|
||||
g++51 -std=c++11
|
||||
g++51 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
|
||||
g++51 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
|
||||
g++51 -std=c++98
|
||||
g++49 -std=c++11
|
||||
g++49 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
|
||||
g++49 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
|
||||
@ -119,12 +108,17 @@ g++47 -std=c++11
|
||||
g++47 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
|
||||
g++47 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
|
||||
g++47 -std=c++98
|
||||
g++46 -std=c++0x -DBETTER_ENUMS_NO_CONSTEXPR
|
||||
g++46 -std=c++0x -DBETTER_ENUMS_NO_CONSTEXPR -DBETTER_ENUMS_STRICT_CONVERSION
|
||||
g++46 -std=c++98
|
||||
g++45 -std=c++0x -DBETTER_ENUMS_NO_CONSTEXPR
|
||||
g++45 -std=c++0x -DBETTER_ENUMS_NO_CONSTEXPR -DBETTER_ENUMS_STRICT_CONVERSION
|
||||
g++45 -std=c++98
|
||||
g++44 -std=c++0x -DBETTER_ENUMS_NO_CONSTEXPR
|
||||
g++44 -std=c++0x -DBETTER_ENUMS_NO_CONSTEXPR -DBETTER_ENUMS_STRICT_CONVERSION
|
||||
g++44 -std=c++98
|
||||
g++43 -std=c++0x -DBETTER_ENUMS_NO_CONSTEXPR
|
||||
g++43 -std=c++98
|
||||
~~~
|
||||
|
||||
%% description =
|
||||
Better Enums compiler support, compatibility, feature detection, and automated
|
||||
testing.
|
||||
%% description = Information about compiler support and feature detection.
|
||||
|
||||
15
doc/Contact.md
Normal file
15
doc/Contact.md
Normal file
@ -0,0 +1,15 @@
|
||||
## Contact
|
||||
|
||||
- Send me an email: [antonbachin@yahoo.com](mailto:antonbachin@yahoo.com).
|
||||
- Visit the [GitHub]($repo) project to open an issue or get a development
|
||||
version.
|
||||
|
||||
I also watch the `enums` tag on Stack Overflow.
|
||||
|
||||
I'm happy to hear any feedback. If you have any trouble using the library or
|
||||
parsing the documentation, please don't hesitate to let me know.
|
||||
|
||||
And, if you find this library helpful, give it a star on GitHub to let me know
|
||||
you use it. It will help keep me encouraged :)
|
||||
|
||||
%% description = Contact information for bugs, issues, support, and feedback.
|
||||
@ -1,269 +0,0 @@
|
||||
## Design decisions FAQ
|
||||
|
||||
$be pushes at the edges of what is possible in standard $cxx, and I've had to
|
||||
make some difficult decisions as a result. You can imagine the set of
|
||||
potential reflective enum implementations as a space, with axes such as "concise
|
||||
syntax," "uniform interface," "compilation speed," "run-time performance," and
|
||||
so on. As is typical in engineering, the constraints are such that as you move
|
||||
to extremes along one axis, you have to retreat along others — for
|
||||
example, some desirable aspects of concise syntax conflict with having a uniform
|
||||
interface, which is nonetheless good for teachability, and compile-time
|
||||
performance is, in some ways, at odds with run-time performance.
|
||||
|
||||
So, there are many variations possible on $be, and, in fact, I have tried and
|
||||
maintained a few. This page describes how I chose the one that is published.
|
||||
The choices are debatable, but I am attempting to record the debate. Hopefully,
|
||||
this will either convince you that I have made a good choice, or, if you
|
||||
disagree, you will have a good starting point for discussion, or even for
|
||||
implementing an alternative.
|
||||
|
||||
I am always looking for new arguments and approaches. If you have an idea,
|
||||
comment, criticism, please do [let me know][contact].
|
||||
|
||||
$internal_toc
|
||||
|
||||
### Why do enum members have underscores?
|
||||
|
||||
Enum members such as `_to_string` occupy the same scope as the names of
|
||||
constants declared by the user. I chose to prefix members with underscores to
|
||||
lessen the chances of collision. For example, take `_valid`, and suppose it was
|
||||
`valid` instead. That would make this enum impossible:
|
||||
|
||||
<em>BETTER_ENUM(Status, char, valid, invalid)</em>
|
||||
|
||||
because the constant `Status::valid` would clash with the member
|
||||
`Status::valid`.
|
||||
|
||||
Of course, users could try to declare constants with underscores as well, but I
|
||||
find it easier to ask users not to do that, rather than ask them to worry about
|
||||
a potentially growing set of reserved names, which they wouldn't fully know even
|
||||
for a single version of Better Enums, without frequently looking at the API
|
||||
documentation.
|
||||
|
||||
Alternatives to this involve separating the namespaces occupied by members and
|
||||
constants. I don't think increasing nesting is an option, since nobody wants to
|
||||
write `Status::values::valid` or `Status::operations::valid`. I don't think
|
||||
moving constants out of `Status` is a good idea, since scoped constants is a
|
||||
feature of Better Enums, which is especially important for $cxx98 usage.
|
||||
|
||||
This leaves the possibility of moving the operations performed by the members
|
||||
into traits types, i.e. something like `traits<Status>::valid`. That is an
|
||||
interesting option, and it has [its own section][traits]. I have tried it, but
|
||||
the verbosity increase is much greater than the benefit of dropping underscores,
|
||||
so I chose not to do it.
|
||||
|
||||
### Why does Better Enums use a macro at all?
|
||||
|
||||
Better Enums needs to turn the names of declared constants into strings, and I
|
||||
don't believe there is any way to do this in standard $cxx except by using the
|
||||
preprocessor's macro parameter stringization operator (`#`). So, at the top
|
||||
level, Better Enums has to provide a macro. I am, however, trying to keep the
|
||||
user-facing macros to a minimum; in particular there is only one.
|
||||
|
||||
I think that's the best that is possible. Furthermore, apart from the macro
|
||||
itself, the declaration looks very similar to a $cxx11 `enum` declaration, with
|
||||
an underlying type, comma-separated constant list, and the same support for
|
||||
initializers as built-in enums. So, I am trying to keep even this one macro out
|
||||
of the user's way. I wouldn't accept any change that involved turning the
|
||||
declaration into a preprocessor sequence or tuple, i.e. something like
|
||||
|
||||
<em>BETTER_ENUM(Channel, int, (Red)(Green)((Blue)(5)))</em>
|
||||
|
||||
even if it promised extra capabilities.
|
||||
|
||||
Better Enums uses additional macros internally, for two main purposes: to do the
|
||||
actual work of stringizing the declared constants and assembling them into
|
||||
arrays, and to configure itself by detecting which compiler it is running on.
|
||||
|
||||
I am not a fan of gratuitous macros, but in these cases they are unavoidable,
|
||||
and, indeed, I am grateful for the stringization operator.
|
||||
|
||||
<a id="NoEnumInsideClass"></a>
|
||||
### Why is it not possible to declare a Better Enum inside a class?
|
||||
|
||||
This is due to an interaction between linkage and `constexpr`.
|
||||
|
||||
1. Better Enums is a header-only library that declares arrays with static
|
||||
storage, such as the array of constant names for each declared enum. Such
|
||||
arrays can be declared in namespace scope, in class scope, or in function
|
||||
scope, but they also need to be defined somewhere.
|
||||
|
||||
If `BETTER_ENUM` is to be usable in both namespace and class scope, it
|
||||
already can't assume that it can declare arrays in namespace scope, since if
|
||||
`BETTER_ENUM` is used in a class, its entire expansion will be enclosed in
|
||||
the declaration of that class.
|
||||
|
||||
That leaves class scope and function scope. If the arrays are declared in
|
||||
class scope, there needs to be a separate definition of them in some
|
||||
translation unit. This is too burdensome for the user, because the separate
|
||||
definition would involve repetition of the constants in the macro parameter
|
||||
list, creating exactly the type of maintenance problem that Better Enums is
|
||||
trying to eliminate.
|
||||
|
||||
Function scope is the only viable option remaining after considering linkage
|
||||
constraints. Each array can be wrapped in a static function, which has a
|
||||
static local variable, which is initialized with the array. The functions can
|
||||
be called to get references to the arrays.
|
||||
|
||||
However....
|
||||
|
||||
2. These arrays need to be accessible to `constexpr` code in $cxx11, and
|
||||
`constexpr` functions are not allowed to have static local variables.
|
||||
|
||||
Ironically, this seems like one place where $cxx98 is more "flexible," but only
|
||||
for the reason that compile-time usage of Better Enums is not supported in
|
||||
$cxx98.
|
||||
|
||||
<a id="Traits"></a>
|
||||
### Should Better Enums provide enum "objects" or traits types?
|
||||
|
||||
A Better Enum value is an "object," whose memory representation is the same as
|
||||
its underlying type. For example,
|
||||
|
||||
<em>BETTER_ENUM(Channel, int, Red, Green, Blue)</em>
|
||||
|
||||
expands to something like
|
||||
|
||||
<em>struct Channel {
|
||||
enum _enumerated : int { Red, Green, Blue };
|
||||
int _value;</em>
|
||||
// Strings array, _to_string, _from_string, etc.
|
||||
<em>};</em>
|
||||
|
||||
---
|
||||
|
||||
There is an alternative interpretation, in which the Better Enums library
|
||||
generates enum traits instead, i.e. the generated arrays and members sit
|
||||
alongside built-in enums instead of wrapping them:
|
||||
|
||||
<em>BETTER_ENUM(Channel, int, Red, Green, Blue)</em>
|
||||
|
||||
generates
|
||||
|
||||
<em>enum class Channel : int { Red, Green, Blue };</em>
|
||||
|
||||
<em>template <>
|
||||
struct ::better_enums::traits<Channel> {
|
||||
using _enumerated = Channel;</em>
|
||||
// Strings array, to_string, from_string, etc.
|
||||
<em>};</em>
|
||||
|
||||
---
|
||||
|
||||
There are a number of advantages to the traits approach.
|
||||
|
||||
- The underscore prefixes can be dropped from member names, since they no longer
|
||||
share a namespace with user-declared constants.
|
||||
- The interface, at first glance, becomes more uniform, since now every member
|
||||
is a static member of the traits type. Without traits, `_to_string` is a
|
||||
non-static member, while `_from_string` is a static member.
|
||||
- `Channel` is one of the language's own enum types, instead of some mystery
|
||||
type provided by Better Enums. This may make it easier to understand. It also
|
||||
eliminates the problem with different syntaxes for `switch` statements
|
||||
described [here][implicit].
|
||||
|
||||
However, it also introduces some difficulties.
|
||||
|
||||
- The syntax is more verbose, since everything becomes a member of the traits
|
||||
type. For example, instead of `Channel::_from_string()`, you get
|
||||
`better_enums::traits<Channel>::from_string()`. The underscore may be
|
||||
unpleasant, but so far I have preferred the underscore to boilerplate.
|
||||
- The uniform interface ends up getting wrapped behind functions anyway, for the
|
||||
sake of type inference. For example, the "naked" `to_string` function is
|
||||
called as `better_enums::traits<Channel>::to_string(channel)`, which is
|
||||
redundant, because the compiler could infer the type parameter `Channel` if it
|
||||
was the parameter of the function instead of the traits type. So, the obvious
|
||||
thing is to define such a wrapper function, which can then be called as
|
||||
`better_enums::to_string(channel)`. No such function can be easily defined for
|
||||
`from_string` and other `from_*` functions, however, because the type
|
||||
parameters can't be inferred from arguments. So, the signatures of `to_*` and
|
||||
`from_*` functions again effectively diverge, negating this advantage of
|
||||
traits. The closest I can get with wrappers is
|
||||
`better_enums::from_string<Channel>`, which has the same signature only in the
|
||||
formal sense, i.e. modulo the difference in type inference.
|
||||
|
||||
I actually think there is a way to infer the type parameter from the return
|
||||
type, similar to how it is done [here][infer], but that will not be suitable
|
||||
for all contexts, and the user may be surprised by ambiguous resolution error
|
||||
messages when it is not.
|
||||
- Scoped constants are lost for $cxx98 unless Better Enums again wraps them in a
|
||||
generated type, though it will be more lightweight than a full Better Enum of
|
||||
the non-traits approach.
|
||||
- Traits types must be specialized in either the same namespace scope they are
|
||||
declared in, or in an enclosing scope. This makes it impossible to declare an
|
||||
enum and specialize traits for it in a user's custom namespace.
|
||||
|
||||
Despite the disadvantages listed just above, I consider the traits approach
|
||||
interesting — it's a close call. There is an
|
||||
[out-of-date branch][traits-branch] containing a traits version of Better Enums.
|
||||
You can see some of the usage in its [samples][traits-samples] directory. I may
|
||||
update it from time to time, especially if there is interest.
|
||||
|
||||
### Why does Better Enums use linear scans for lookup?
|
||||
|
||||
It seems that Better Enums needs to use the same algorithms at compile time as
|
||||
at run time, because I have not found a way (and doubt there is one) to
|
||||
determine, during the execution of a `constexpr` function, whether it is
|
||||
executing at compile time or at run time. So, whatever data structures I use to
|
||||
accelerate lookup, I have to generate them at compile time, to be available as
|
||||
early as possible.
|
||||
|
||||
I tried to generate various data structures at compile time, but so far,
|
||||
generation has been too slow. The fastest algorithm so far, a compile-time merge
|
||||
sort based on template parameter packs, took over 100ms to run on the constant
|
||||
set of a large enum. I would have to run three of these per enum — for the
|
||||
constants, for the names, and for the names with case-insensitive comparison.
|
||||
This results in a 300ms slowdown per enum, which is not acceptable, given that
|
||||
on my system the same compiler takes 370ms to process `iostream`, and less than
|
||||
10ms to process an enum without acceleration data structures. Declaring five
|
||||
large enums with accelerated lookup would take 1.5 seconds of compilation time.
|
||||
This doesn't scale to large projects with many translation units.
|
||||
|
||||
I am continuing to look for faster algorithms or better approaches, so faster
|
||||
lookup may be coming to Better Enums in the future.
|
||||
|
||||
So far, I have tried Boost.MPL sort, Eric Niebler's Meta sort, my own selection
|
||||
sort based on `constexpr`, and an insertion and merge sort based on parameter
|
||||
packs. I cannot use (Boost?).Hana sort, because that requires $cxx14. I am also
|
||||
considering various hash table-like data structures, and providing two sets of
|
||||
interfaces for compile-time and run-time usage, which is something I would
|
||||
really rather not have to do. The latter option would be worth considering,
|
||||
however, if I measured a significant improvement in running time from better
|
||||
data structures — something I haven't gotten to yet because there doesn't
|
||||
seem to be a data structure to measure that is not disqualified by the speed of
|
||||
generation.
|
||||
|
||||
### Why not use indices for the representation?
|
||||
|
||||
Representing Better Enum values by their indices in the declaration list seems
|
||||
like a tempting solution for the problem of having multiple constants with the
|
||||
same numeric value. It also speeds up some operations. For example, if a Better
|
||||
Enum is simply an index, then getting its string representation is simply
|
||||
indexing an array, rather than some kind of data structure lookup.
|
||||
|
||||
// Representations 0, 1, 2, 3 instead of 1, 2, 3, 1.
|
||||
<em>BETTER_ENUM(Kind, int, A = 1, B, C, D = A)</em>
|
||||
|
||||
Choosing this approach has serious drawbacks.
|
||||
|
||||
- The data structure lookup has simply been moved to another place. It now takes
|
||||
time to convert from a literal `Kind::D` to a Better Enum.
|
||||
- It is still impossible to disambiguate between the literals `Kind::D` and
|
||||
`Kind::A` (1 and 1). Only the Better Enums objects of type `Kind` that
|
||||
represent `D` and `A` are different from each other (0 and 3). This is not
|
||||
only a technical problem, but is also quite unintuitive.
|
||||
- Treating a Better Enum represented by an index as untyped memory produces
|
||||
surprising results. This makes Better Enums much less useful with functions
|
||||
such as `fwrite`. Worse, Better Enums become sensitive to declaration order
|
||||
even when initializers are given explicitly. Using indices for the
|
||||
representation makes it difficult to maintain compatibility with external
|
||||
protocols and file formats.
|
||||
|
||||
[contact]: ${prefix}Contact.html
|
||||
[traits]: #Traits
|
||||
[implicit]: ${prefix}OptInFeatures.html#StrictConversions
|
||||
[infer]: ${prefix}demo/SpecialValues.html
|
||||
[traits-branch]: $repo/tree/traits
|
||||
[traits-samples]: $repo/tree/traits/samples
|
||||
|
||||
%% description = Better Enums design decisions and tradeoffs.
|
||||
@ -1,8 +1,8 @@
|
||||
## Extending limits
|
||||
|
||||
The `BETTER_ENUM` macro makes heavy use of the preprocessor, and some of the
|
||||
internal macros have size limits. There are two: on the number of constants you
|
||||
can declare, and on the maximum length of a constant name under very specific
|
||||
The `ENUM` macro makes heavy use of the preprocessor, and some of the internal
|
||||
macros have size limits. There are two: on the number of constants you can
|
||||
declare, and on the maximum length of a constant name under very specific
|
||||
conditions. If you run into either one, you can extend the limit by following
|
||||
the instructions on this page.
|
||||
|
||||
@ -19,7 +19,7 @@ constants of full-`constexpr` enums. To extend:
|
||||
example. Add 1 to the number of characters to account for the null
|
||||
terminator — our numbers are now 512 and 64.
|
||||
2. Get `make_macros.py` from your copy of the full Better Enums distribution
|
||||
or from <a href="https://raw.githubusercontent.com/aantron/better-enums/$ref/script/make_macros.py" download>GitHub</a>.
|
||||
or from <a href="https://raw.githubusercontent.com/aantron/better-enums/$version/script/make_macros.py" download>GitHub</a>.
|
||||
3. You will run this script to generate a header file containing some
|
||||
replacement macros for `enum.h` to use. Pick a name for this file and a
|
||||
location somewhere in your include path. I will assume that this file is
|
||||
@ -31,38 +31,10 @@ constants of full-`constexpr` enums. To extend:
|
||||
|
||||
- For g++ and clang++, `-DBETTER_ENUMS_MACRO_FILE='<common/enum_macros.h>'`
|
||||
- For VC++, `\DBETTER_ENUMS_MACRO_FILE='<common/enum_macros.h>'`
|
||||
- With CMake, you may need something like
|
||||
`add_definitions(-DBETTER_ENUMS_MACRO_FILE="$${CMAKE_SOURCE_DIR}/src/enum-macros.h")`
|
||||
|
||||
You can also create a new header file that defines this macro, and then
|
||||
includes `enum.h`. Then, include your new file everywhere where you would
|
||||
otherwise include `enum.h`:
|
||||
|
||||
~~~comment
|
||||
<em>#pragma once
|
||||
|
||||
#define BETTER_ENUMS_MACRO_FILE <common/enum_macros.h>
|
||||
#include <enum.h></em>
|
||||
~~~
|
||||
|
||||
6. Enjoy the looser limits. Just watch out — increasing the second
|
||||
number can really slow down compilation of full-`constexpr` enums.
|
||||
7. You don't need `make_macros.py` anymore. It's not part of your build
|
||||
process and you can delete it.
|
||||
|
||||
---
|
||||
|
||||
I am paying attention to feedback, so if more than a few users say that the
|
||||
default limit of 64 constants is too low, I will increase it to simplify
|
||||
everyone's command line. The current choice of 64 is basically an arbitrary
|
||||
guess, loosely informed by the following two facts about macro parameter limits:
|
||||
|
||||
- The default limit in Boost.Preprocessor is 64. Though Better Enums does not
|
||||
use Boost, I took this number as a guideline.
|
||||
- The next power of two, 128, is more than [the number Visual C++ supports][vc]
|
||||
(127).
|
||||
|
||||
[vc]: https://msdn.microsoft.com/en-us/library/ft39hh4x.aspx
|
||||
|
||||
%% description =
|
||||
How to extend limits imposed by internal macros in Better Enums.
|
||||
%% description = How to extend limits imposed by internal macros.
|
||||
|
||||
35
doc/Makefile
35
doc/Makefile
@ -1,36 +1,23 @@
|
||||
toexample = ../example/$(notdir $(1:.md=.cc))
|
||||
SOURCE_MARKDOWN := $(wildcard tutorial/*) $(wildcard demo/*)
|
||||
SOURCE_CXX := $(SOURCE_MARKDOWN:.md=.cc)
|
||||
|
||||
SOURCE_MARKDOWN := $(wildcard tutorial/*.md) $(wildcard demo/*.md)
|
||||
SOURCE_CXX := $(foreach md,$(SOURCE_MARKDOWN),$(call toexample,$(md)))
|
||||
.PHONY : all
|
||||
all : html examples
|
||||
|
||||
.PHONY : html
|
||||
html :
|
||||
python docs.py
|
||||
@echo "See html/index.html"
|
||||
|
||||
.PHONY : publish
|
||||
publish : prepare
|
||||
cp -r html/* ../doc-publish
|
||||
cd ../doc-publish && git add . && git commit --amend --reset-author && \
|
||||
git push -f
|
||||
|
||||
.PHONY : prepare
|
||||
prepare : examples web
|
||||
|
||||
.PHONY : web
|
||||
web : examples
|
||||
python docs.py --web
|
||||
|
||||
.PHONY : examples
|
||||
examples : $(SOURCE_CXX)
|
||||
examples : clean-examples $(SOURCE_CXX)
|
||||
|
||||
define EXAMPLE
|
||||
$(1) : $(2)
|
||||
python transform.py --o-cxx $(1) $(2)
|
||||
endef
|
||||
.PHONY : clean-examples
|
||||
clean-examples :
|
||||
make -C ../example clean
|
||||
rm -f ../example/*.cc
|
||||
|
||||
$(foreach md,$(SOURCE_MARKDOWN), \
|
||||
$(eval $(call EXAMPLE,$(call toexample,$(md)),$(md))))
|
||||
%.cc : %.md
|
||||
python transform.py --o-cxx ../example/$(notdir $@) $<
|
||||
|
||||
.PHONY : clean
|
||||
clean :
|
||||
|
||||
@ -6,27 +6,6 @@ default. Read this page if you want to enable them.
|
||||
|
||||
$internal_toc
|
||||
|
||||
### Default constructors
|
||||
|
||||
Better Enums generate with inaccessible (private or deleted) default
|
||||
constructors. This is meant to help control where in your program Better Enums
|
||||
values are introduced, and thus ensure that only valid, properly initialized
|
||||
enum values are ever created.
|
||||
|
||||
If you want Better Enums to have a default constructor, you can do something
|
||||
like the following:
|
||||
|
||||
~~~
|
||||
<em>#define</em> <em>BETTER_ENUMS_DEFAULT_CONSTRUCTOR</em>(<em>Enum</em>) \
|
||||
<em>public</em>: \
|
||||
<em>Enum()</em> = <em>default</em>;
|
||||
|
||||
<em>#include</em> <<em>enum.h</em>>
|
||||
~~~
|
||||
|
||||
You can put this in its own header file, and include that header file instead of
|
||||
including `enum.h` directly.
|
||||
|
||||
### Compile-time name trimming
|
||||
|
||||
This makes `_to_string` and `_names` `constexpr`, i.e. "full" `constexpr` mode.
|
||||
@ -43,8 +22,7 @@ slow enums to get the same penalty as including `iostream` — but it is
|
||||
a steep penalty nonetheless. I don't think most people need this feature most of
|
||||
the time, so it's too high a price to pay. If I improve compilation times to the
|
||||
point where compile-time name trimming can be the default, I will simply
|
||||
redefine `SLOW_ENUM` as `BETTER_ENUM` and deprecate it, so your code will still
|
||||
work.
|
||||
redefine `SLOW_ENUM` as `ENUM` and deprecate it, so your code will still work.
|
||||
|
||||
### Strict conversions
|
||||
|
||||
@ -86,17 +64,5 @@ Here they are:
|
||||
case <em>+</em>Channel::Blue: break;
|
||||
}
|
||||
|
||||
%% description = Optional Better Enums features, disabled by default for
|
||||
performance or compatibility reasons.
|
||||
|
||||
### Injecting tokens
|
||||
|
||||
You can define `BETTER_ENUMS_CLASS_ATTRIBUTE` before declaring a Better Enum, to
|
||||
inject tokens into the class declaration. For example, in
|
||||
|
||||
#define <em>BETTER_ENUMS_CLASS_ATTRIBUTE</em> <em>__attribute__(foo)</em>
|
||||
<em>BETTER_ENUM</em>(<em>Channel</em>, int, Red, Green, Blue)
|
||||
|
||||
The resulting enum declaration will begin with
|
||||
|
||||
class <em>__attribute__(foo)</em> <em>Channel</em> {
|
||||
%% description = Opting into features disabled by default for performance or
|
||||
compatibility reasons.
|
||||
|
||||
@ -7,9 +7,9 @@ to get a rough idea of how long it takes to compile Better Enums.
|
||||
|
||||
The files compared in the test are as follows:
|
||||
|
||||
- [One file]($repo/blob/$ref/test/performance/4-declare_enums.cc) includes
|
||||
- [One file]($repo/blob/$version/test/performance/4-declare_enums.cc) includes
|
||||
`enum.h` and declares 647 constants across 36 Better Enums.
|
||||
- The [other file]($repo/blob/$ref/test/performance/5-iostream.cc) *only*
|
||||
- The [other file]($repo/blob/$version/test/performance/5-iostream.cc) *only*
|
||||
includes `iostream` and does nothing with it.
|
||||
|
||||
The argument is that if compiling a bunch of Better Enums is faster, or about as
|
||||
@ -29,22 +29,4 @@ compiled faster.
|
||||
- gcc 5.1, full `constexpr`: 4.23
|
||||
- VC2015RC, $cxx98: 1.18
|
||||
|
||||
The time to merely include `enum.h` vary widely by compiler, with clang being
|
||||
by far the fastest. The ratios to `iostream` are given below.
|
||||
|
||||
- clang 3.6: 0.15
|
||||
- gcc 5.1: 0.77
|
||||
- VC2015RC: 0.82
|
||||
|
||||
On my test machines, clang processed the file in 40ms, gcc took 230ms, and
|
||||
VC2015 took 820ms. The first two are comparable to each other, but VC2015 runs
|
||||
on a different machine.
|
||||
|
||||
---
|
||||
|
||||
In general, I am very sensitive to performance. Better Enums was originally
|
||||
developed in the context of a commercial project where slow running times *and*
|
||||
slow compilation times were unacceptable. I am continuing to develop it in this
|
||||
spirit.
|
||||
|
||||
%% description = Better Enums compilation speed and performance testing results.
|
||||
%% description = Compilation performance testing results.
|
||||
|
||||
@ -11,19 +11,13 @@ pre, code, samp, h4, .contents ul {
|
||||
Consolas, "Liberation Mono", Menlo, "Courier New", Courier, monospace;
|
||||
}
|
||||
|
||||
h1, .splash-text .self, nav .self {
|
||||
font-family: Georgia, Times, "Times New Roman", serif;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: #477093;
|
||||
padding: 1.5em 20px;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
overflow: scroll;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
font-size: 78%;
|
||||
max-width: 84ex;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
pre em {
|
||||
@ -51,35 +45,21 @@ code, samp {
|
||||
}
|
||||
|
||||
.container {
|
||||
margin-left: 150px;
|
||||
margin-right: 150px;
|
||||
max-width: 760px;
|
||||
margin-left: 230px;
|
||||
}
|
||||
|
||||
.main .container > * {
|
||||
max-width: 41em;
|
||||
}
|
||||
|
||||
.index .main .container > * {
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.main .container > .contents {
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
@media (max-width: 1400px) {
|
||||
@media (max-width: 1220px) {
|
||||
.container {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: 1100px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1120px) {
|
||||
@media (max-width: 780px) {
|
||||
.container {
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@ -99,17 +79,6 @@ nav, .spacer {
|
||||
background-color: #222;
|
||||
}
|
||||
|
||||
nav > * > span {
|
||||
float: right;
|
||||
opacity: 0.9;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
nav .self {
|
||||
font-size: 16px;
|
||||
padding-right: 0.5em;
|
||||
}
|
||||
|
||||
nav a {
|
||||
margin-right: 2em;
|
||||
}
|
||||
@ -134,38 +103,13 @@ header {
|
||||
background: linear-gradient(#395E7E, #4A79A0);
|
||||
color: white;
|
||||
padding: 50px 0;
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0;
|
||||
font-size: 60px;
|
||||
font-weight: normal;
|
||||
text-shadow: -2px 2px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
header section {
|
||||
float: left;
|
||||
}
|
||||
|
||||
header section.buttons, header section.notes {
|
||||
float: right;
|
||||
margin-top: 1.75em;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
header section.notes {
|
||||
max-width: 20em;
|
||||
font-size: 75%;
|
||||
margin-right: 10px;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
header section.notes p {
|
||||
margin: 0.35em 0.35em;
|
||||
}
|
||||
|
||||
header section.notes code {
|
||||
background-color: transparent;
|
||||
font-weight: 100;
|
||||
}
|
||||
|
||||
header h2 {
|
||||
@ -185,41 +129,10 @@ header h3 {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.buttons a {
|
||||
display: block;
|
||||
background-color: rgba(255, 255, 255, 0.2) !important;
|
||||
width: 10em;
|
||||
text-align: center;
|
||||
margin-bottom: 0.5em;
|
||||
padding: 0.25em 0;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.buttons a:hover {
|
||||
background-color: white !important;
|
||||
color: #395E7E;
|
||||
}
|
||||
|
||||
@media (max-width: 1000px) {
|
||||
header .notes {
|
||||
display: none;
|
||||
}
|
||||
|
||||
header .buttons {
|
||||
margin-right: 2em;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 660px) {
|
||||
header .buttons {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-top: 2em;
|
||||
font-size: 36px;
|
||||
font-weight: 300;
|
||||
font-weight: 100;
|
||||
}
|
||||
|
||||
hr {
|
||||
@ -229,20 +142,20 @@ hr {
|
||||
|
||||
footer {
|
||||
font-size: 14px;
|
||||
margin-top: 100px;
|
||||
margin-top: 150px;
|
||||
margin-bottom: 20px;
|
||||
opacity: 0.5;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
/*background-color: red;*/
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
a[href=""] {
|
||||
color: white !important;
|
||||
/*background-color: red !important;*/
|
||||
background-color: red !important;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
@ -253,10 +166,6 @@ header a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.main {
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
.main a[href], footer a[href] {
|
||||
background-color: #edd;
|
||||
color: #844;
|
||||
@ -306,6 +215,7 @@ span#note:target {
|
||||
|
||||
.main h3 {
|
||||
font-size: 30px;
|
||||
font-weight: 100;
|
||||
margin-top: 2em;
|
||||
color: black;
|
||||
}
|
||||
@ -378,45 +288,15 @@ li {
|
||||
}
|
||||
|
||||
.blurbs > li {
|
||||
width: 45%;
|
||||
float: left;
|
||||
min-height: 5em;
|
||||
}
|
||||
|
||||
@media (min-width: 1076px) {
|
||||
.blurbs > li {
|
||||
width: 28%;
|
||||
margin-right: 4%;
|
||||
}
|
||||
|
||||
.blurbs > li.zero-mod-three {
|
||||
.blurbs > li.even {
|
||||
clear: both;
|
||||
margin-left: 2%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1075px) {
|
||||
.blurbs > li {
|
||||
width: 45%;
|
||||
margin-right: 4%;
|
||||
}
|
||||
|
||||
.blurbs > li.zero-mod-two {
|
||||
clear: both;
|
||||
margin-left: 2%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 620px) {
|
||||
.blurbs > li {
|
||||
float: none;
|
||||
width: 100%;
|
||||
min-height: 3em;
|
||||
}
|
||||
|
||||
.blurbs > li.zero-mod-two {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
margin-left: 3%;
|
||||
margin-right: 6%;
|
||||
}
|
||||
|
||||
.blurbs strong {
|
||||
@ -431,6 +311,19 @@ li {
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@media (max-width: 620px) {
|
||||
.blurbs > li {
|
||||
float: none;
|
||||
width: 100%;
|
||||
min-height: 3em;
|
||||
}
|
||||
|
||||
.blurbs > li.even {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.act strong {
|
||||
font-weight: bold;
|
||||
font-size: 120%;
|
||||
@ -449,25 +342,9 @@ li {
|
||||
padding-left: 25px;
|
||||
}
|
||||
|
||||
.splash-text {
|
||||
padding-top: 1em;
|
||||
font-size: 150%;
|
||||
font-weight: normal;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.splash-text em {
|
||||
border-bottom: 1px solid #888;
|
||||
}
|
||||
|
||||
.splash-text .self {
|
||||
color: #777;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
.splash {
|
||||
float: right;
|
||||
text-align: center;
|
||||
margin-left: -10%;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@ -477,22 +354,12 @@ li {
|
||||
|
||||
.splash pre.left {
|
||||
text-align: right;
|
||||
color: black;
|
||||
font-weight: bold;
|
||||
color: inherit;
|
||||
background-color: transparent;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.splash pre.right {
|
||||
text-align: left;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
@media (max-width: 1000px) {
|
||||
.splash {
|
||||
float: none;
|
||||
margin-left: -10%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 700px) {
|
||||
@ -518,7 +385,6 @@ h4 {
|
||||
color: #888;
|
||||
padding-top: 1em;
|
||||
white-space: nowrap;
|
||||
font-size: 125%;
|
||||
}
|
||||
|
||||
h4 em {
|
||||
@ -528,9 +394,9 @@ h4 em {
|
||||
}
|
||||
|
||||
.api ul.contents {
|
||||
-webkit-columns: 300px 3;
|
||||
-moz-columns: 300px 3;
|
||||
columns: 300px 3;
|
||||
-webkit-columns: 300px 2;
|
||||
-moz-columns: 300px 2;
|
||||
columns: 300px 2;
|
||||
}
|
||||
|
||||
.api ul.contents > li {
|
||||
@ -541,7 +407,6 @@ h4 em {
|
||||
|
||||
.main h3 {
|
||||
margin-top: 4em;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
h3.contents {
|
||||
@ -560,36 +425,3 @@ h3.contents {
|
||||
margin-top: 0;
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
|
||||
.buttons-bar {
|
||||
background-color: #f4f4f4;
|
||||
padding-top: 0.5em;
|
||||
padding-bottom: 0.5em;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.buttons-bar a img {
|
||||
margin-right: 25px;
|
||||
}
|
||||
|
||||
.buttons-bar iframe.gh-button {
|
||||
width: 95px;
|
||||
}
|
||||
|
||||
.buttons-bar .tweet-share,
|
||||
.buttons-bar .gh-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.index .buttons-bar .tweet-share,
|
||||
.index .buttons-bar .gh-button {
|
||||
display: initial;
|
||||
}
|
||||
|
||||
.buttons-bar iframe.gh-watch {
|
||||
width: 103px;
|
||||
}
|
||||
|
||||
.external {
|
||||
font-size: 75%;
|
||||
}
|
||||
|
||||
@ -46,10 +46,10 @@ A macro allows us to override the invalid value by specializing the template:
|
||||
|
||||
Now, we can declare enums like these:
|
||||
|
||||
BETTER_ENUM(<em>Channel</em>, int, Red, Green, Blue, <em>Invalid</em>)
|
||||
ENUM(<em>Channel</em>, int, Red, Green, Blue, <em>Invalid</em>)
|
||||
// Invalid is the invalid value by default
|
||||
|
||||
BETTER_ENUM(<em>Compression</em>, int, <em>Undefined</em>, None, Huffman)
|
||||
ENUM(<em>Compression</em>, int, <em>Undefined</em>, None, Huffman)
|
||||
OVERRIDE_INVALID(<em>Compression</em>, <em>Undefined</em>)
|
||||
|
||||
and use them:
|
||||
@ -71,7 +71,7 @@ slightly more complex template function for the general case:
|
||||
constexpr <em>Enum default_imp</em>l()
|
||||
{
|
||||
return
|
||||
<em>Enum::_size() < 2 ?
|
||||
<em>Enum::_size < 2 ?
|
||||
throw std::logic_error("enum has no valid constants") :
|
||||
Enum::_values()[0] == invalid_impl<Enum>() ?
|
||||
Enum::_values()[1] :
|
||||
@ -100,7 +100,7 @@ And, as before, the usage:
|
||||
|
||||
And, if you do
|
||||
|
||||
BETTER_ENUM(<em>Answer</em>, int, Yes, No, <em>Invalid</em>)
|
||||
ENUM(<em>Answer</em>, int, Yes, No, <em>Invalid</em>)
|
||||
// OVERRIDE_DEFAULT(<em>Answer</em>, <em>Invalid</em>)
|
||||
|
||||
you will get a helpful compile-time error saying
|
||||
@ -170,6 +170,5 @@ There are many possible variations of these policies, but I think most of them
|
||||
can be encoded in a reasonable fashion using the tools Better Enums provides.
|
||||
Enjoy!
|
||||
|
||||
%% description = An example that uses Better Enums compile-time reflection to
|
||||
create invalid and default values for each enum, enforced statically by the
|
||||
compiler, for readability and maintainability.
|
||||
%% description = Encoding project policies for static enforcement using Better
|
||||
Enums.
|
||||
|
||||
@ -17,7 +17,7 @@ We simply need to find the maximum value of any given enum type.
|
||||
constexpr <em>Enum max_loop</em>(Enum accumulator, size_t index)
|
||||
{
|
||||
return
|
||||
<em>index >= Enum::_size() ? accumulator :
|
||||
<em>index >= Enum::_size ? accumulator :
|
||||
Enum::_values()[index] > accumulator ?
|
||||
max_loop<Enum>(Enum::_values()[index], index + 1) :
|
||||
max_loop<Enum>(accumulator, index + 1)</em>;
|
||||
@ -38,7 +38,7 @@ Now, we can have bit sets that are wide enough to hold whatever range we
|
||||
declared. We just declare enums, and the numeric values of their constants will
|
||||
be bit indices. The rest is straightforward.
|
||||
|
||||
BETTER_ENUM(<em>EFLAGS</em>, int,
|
||||
ENUM(<em>EFLAGS</em>, int,
|
||||
<em>Carry</em>, <em>Parity</em> = 2, <em>Adjust</em> = 4, <em>Zero</em>, <em>Sign</em>, <em>Trap</em>, <em>Interrupt</em>, <em>Direction</em>,
|
||||
<em>Overflow</em>, <em>NestedTask</em> = 14, <em>Resume</em> = 16, <em>V8086</em>, <em>AlignmentCheck</em>,
|
||||
<em>CPUIDPresent</em> = 21)
|
||||
@ -65,5 +65,5 @@ static_assert(max<EFLAGS>()._to_integral() < 32,
|
||||
"some bit indices are out of range");
|
||||
~~~
|
||||
|
||||
%% description = Finding the maximum value of a Better Enum for use in declaring
|
||||
statically-sized bit set types.
|
||||
%% description = Finding the maximum value of a Better Enum constant for use in
|
||||
declaring bit set types.
|
||||
@ -8,7 +8,7 @@ buffer for the definition at compile time.
|
||||
Ok, so it's not really a quine, because we won't be writing all the code needed
|
||||
to generate the definition to the buffer as well. And, there are better ways to
|
||||
dump the definition than shown here. You could simply define a macro that
|
||||
expands to an `BETTER_ENUM` declaration and also stringizes it.
|
||||
expands to an `ENUM` declaration and also stringizes it.
|
||||
|
||||
But that's not the point here. The point of this page is to show some of the
|
||||
reflective capabilities of Better Enums, so you can adapt them for cases where a
|
||||
@ -37,8 +37,8 @@ since we will be calling `_to_string`. Let's make sure it's enabled by defining
|
||||
|
||||
Now, let's declare some enums to dump later:
|
||||
|
||||
BETTER_ENUM(<em>Channel</em>, int, Red, Green, Blue)
|
||||
BETTER_ENUM(<em>Depth</em>, int, TrueColor = 1, HighColor = 0)
|
||||
ENUM(<em>Channel</em>, int, Red, Green, Blue)
|
||||
ENUM(<em>Depth</em>, int, TrueColor = 1, HighColor = 0)
|
||||
|
||||
|
||||
|
||||
@ -82,7 +82,7 @@ initializers for sequential values, but I won't go through this exercise here.
|
||||
constexpr <em>size_t constants_length</em>(size_t index = 0, size_t accumulator = 0)
|
||||
{
|
||||
return
|
||||
<em>index >= Enum::_size() ? accumulator :
|
||||
<em>index >= Enum::_size ? accumulator :
|
||||
constants_length<Enum>(
|
||||
index + 1, accumulator
|
||||
+ string_length(", ")
|
||||
@ -102,7 +102,7 @@ the whole enum:
|
||||
constexpr <em>size_t declaration_length</em>()
|
||||
{
|
||||
return
|
||||
<em>string_length("BETTER_ENUM(")
|
||||
<em>string_length("ENUM(")
|
||||
+ string_length(Enum::_name())
|
||||
+ string_length(", int")
|
||||
+ constants_length<Enum>()
|
||||
@ -129,7 +129,7 @@ so that we can do a sanity check on it.
|
||||
{
|
||||
size_t offset = 0;
|
||||
|
||||
offset += std::sprintf(buffer, <em>"BETTER_ENUM(%s, int", Enum::_name()</em>);
|
||||
offset += std::sprintf(buffer, <em>"ENUM(%s, int", Enum::_name()</em>);
|
||||
|
||||
<em>for</em> (<em>Enum value</em> : <em>Enum::_values()</em>) {
|
||||
offset +=
|
||||
@ -166,10 +166,8 @@ Now, we can write and run this code.
|
||||
It prints:
|
||||
|
||||
~~~comment
|
||||
BETTER_ENUM(Channel, int, Red = 0, Green = 1, Blue = 2)
|
||||
BETTER_ENUM(Depth, int, TrueColor = 1, HighColor = 0)
|
||||
ENUM(Channel, int, Red = 0, Green = 1, Blue = 2)
|
||||
ENUM(Depth, int, TrueColor = 1, HighColor = 0)
|
||||
~~~
|
||||
|
||||
%% description = Have a Better Enum print its own definition. Shows how to
|
||||
compute the amount of memory necessary from the reflective information provided
|
||||
by a Better Enum.
|
||||
%% description = Contrived example that shows static memory allocation.
|
||||
@ -1,173 +0,0 @@
|
||||
## C++17 reflection proposal
|
||||
|
||||
*You can try this demo [live online][live].*
|
||||
|
||||
Better Enums can be used to implement the enums portion of the
|
||||
[$cxx17 reflection proposal N4428][n4428] in $cxx11. N4428 proposes the
|
||||
following traits interface:
|
||||
|
||||
~~~comment
|
||||
<em>namespace std {
|
||||
|
||||
template <typename E>
|
||||
struct enum_traits {
|
||||
struct enumerators {
|
||||
constexpr static size_t size;
|
||||
|
||||
template <size_t I>
|
||||
struct get {
|
||||
constexpr string_literal identifier;
|
||||
constexpr static E value;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
}</em>
|
||||
~~~
|
||||
|
||||
So, the basic usage would be:
|
||||
|
||||
~~~comment
|
||||
<em>enum class Foo {A, B, C};
|
||||
|
||||
constexpr size_t size =
|
||||
std::enum_traits<Foo>::enumerators::size;
|
||||
|
||||
constexpr Foo value_0 =
|
||||
std::enum_traits<Foo>::enumerators::get<0>::value;
|
||||
|
||||
constexpr string_literal name_1 =
|
||||
std::enum_traits<Foo>::enumerators::get<1>::identifier;</em>
|
||||
~~~
|
||||
|
||||
Resulting in the values `3`, `Foo::A`, and `"B"`, respectively.
|
||||
|
||||
---
|
||||
|
||||
The interface is implemented in the optional header file
|
||||
[`extra/better-enums/n4428.h`][header]. There is a necessary difference: the
|
||||
interface is only available for enums declared through the `BETTER_ENUM` macro.
|
||||
This is because the macro is what generates the information necessary for
|
||||
reflection.
|
||||
|
||||
### Demo
|
||||
|
||||
So, with that out of the way, we can do a little test. Let's assume that
|
||||
`extra/` has been added as a directory to search for include files.
|
||||
|
||||
#ifndef BETTER_ENUMS_CONSTEXPR_TO_STRING
|
||||
#define BETTER_ENUMS_CONSTEXPR_TO_STRING
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
<em>#include</em> <<em>enum.h</em>>
|
||||
<em>#include</em> <<em>better-enums/n4428.h</em>>
|
||||
|
||||
---
|
||||
|
||||
Let's declare an enum:
|
||||
|
||||
<em>BETTER_ENUM</em>(<em>Channel</em>, <em>char</em>, <em>Red</em> = <em>1</em>, <em>Green</em>, <em>Blue</em>)
|
||||
|
||||
...and try N4428:
|
||||
|
||||
constexpr std::size_t <em>size</em> =
|
||||
<em>std</em>::<em>enum_traits</em><<em>Channel</em>>::<em>enumerators</em>::<em>size</em>;
|
||||
|
||||
constexpr Channel <em>value_0</em> =
|
||||
<em>std</em>::<em>enum_traits</em><<em>Channel</em>>::<em>enumerators</em>::<em>get</em><<em>0</em>>::<em>value</em>;
|
||||
|
||||
constexpr Channel <em>value_1</em> =
|
||||
<em>std</em>::<em>enum_traits</em><<em>Channel</em>>::<em>enumerators</em>::<em>get</em><<em>1</em>>::<em>value</em>;
|
||||
|
||||
constexpr const char *<em>identifier_2</em> =
|
||||
<em>std</em>::<em>enum_traits</em><<em>Channel</em>>::<em>enumerators</em>::<em>get</em><<em>2</em>>::<em>identifier</em>;
|
||||
|
||||
...and check the results:
|
||||
|
||||
static_assert(<em>size</em> == <em>3</em>, "");
|
||||
|
||||
static_assert(<em>value_0</em> == +<em>Channel::Red</em>, "");
|
||||
static_assert(<em>value_1</em> == +<em>Channel::Green</em>, "");
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout << <em>identifier_2</em> << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
That prints `Blue`, as you would expect.
|
||||
|
||||
### Quirk
|
||||
|
||||
The reason for the `#define` in the code above is that there is one quirk:
|
||||
the interface above is available only for Better Enums for which
|
||||
[compile-time name trimming][slow-enum] is enabled — those declared when
|
||||
`BETTER_ENUMS_CONSTEXPR_TO_STRING` was defined, or declared with the `SLOW_ENUM`
|
||||
variant of `BETTER_ENUM`. As mentioned on the linked page, the reason
|
||||
compile-time name trimming is not the default is that, while still pretty fast,
|
||||
it is four times slower than program-startup-time name trimming. The latter is
|
||||
the default.
|
||||
|
||||
Despite the above, a variation on the interface is available for enums without
|
||||
compile-time name trimming:
|
||||
|
||||
~~~comment
|
||||
<em>namespace std {
|
||||
|
||||
template <typename E>
|
||||
struct enum_traits {
|
||||
struct enumerators {
|
||||
constexpr static size_t size;
|
||||
|
||||
template <size_t I>
|
||||
struct get {
|
||||
constexpr const char *identifier;
|
||||
constexpr static E value;
|
||||
};
|
||||
|
||||
</em>// For enums without compile-time name trimming.<em>
|
||||
template <size_t I>
|
||||
struct get_alt {
|
||||
static const char* identifier();
|
||||
constexpr static E value;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
}</em>
|
||||
~~~
|
||||
|
||||
As you can see, the difference is that `identifier` is a non-`constexpr`
|
||||
function, and you have to access it through `get_alt<I>`.
|
||||
|
||||
~~~comment
|
||||
// Without compile-time name trimming.
|
||||
<em>BETTER_ENUM(Depth, int, HighColor, TrueColor)
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout
|
||||
<< std::enum_traits<Depth>::enumerators::get_alt<1>::identifier()
|
||||
<< std::endl;
|
||||
|
||||
return 0;
|
||||
}</em>
|
||||
~~~
|
||||
|
||||
### The future
|
||||
|
||||
N4428 is the fourth in a series of revisions: [N3815][n3815], [N4027][n4027],
|
||||
[N4113][n4113], N4428. If there are more revisions that change the proposal for
|
||||
enums, I will try to implement those as well.
|
||||
|
||||
[n4428]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4428.pdf
|
||||
[n4113]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4113.pdf
|
||||
[n4027]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4027.pdf
|
||||
[n3815]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3815.html
|
||||
[slow-enum]: ${prefix}OptInFeatures.html#CompileTimeNameTrimming
|
||||
[header]: https://github.com/aantron/better-enums/blob/$ref/extra/better-enums/n4428.h
|
||||
[live]: http://melpon.org/wandbox/permlink/QelcwZNLi4gIx8Ux
|
||||
|
||||
%% description = Approximate implementation of N4428 enum reflection based on
|
||||
Better Enums.
|
||||
32
doc/docs.py
32
doc/docs.py
@ -7,8 +7,6 @@ import string
|
||||
import transform
|
||||
import os
|
||||
import os.path
|
||||
import sys
|
||||
import urllib
|
||||
|
||||
TEMPLATE_DIRECTORY = "template"
|
||||
OUTPUT_DIRECTORY = "html"
|
||||
@ -85,24 +83,15 @@ def compose_page(relative_path, definitions):
|
||||
definitions["canonical"] = canonical
|
||||
definitions["prefix"] = prefix
|
||||
|
||||
definitions["quoted_url"] = urllib.quote(definitions["canonical"], "")
|
||||
definitions["quoted_title"] = urllib.quote(definitions["title"], "")
|
||||
|
||||
if "class" not in definitions:
|
||||
definitions["class"] = ""
|
||||
|
||||
text = templates["page"]
|
||||
text = scrub_comments(text)
|
||||
|
||||
while True:
|
||||
new_text = scrub_comments(text)
|
||||
new_text = re.sub("\$\$", "$$$$", new_text)
|
||||
new_text = apply_template(new_text, definitions)
|
||||
|
||||
if new_text == text:
|
||||
text = apply_template(new_text, definitions)
|
||||
break
|
||||
|
||||
text = new_text
|
||||
while '$' in text:
|
||||
text = apply_template(text, definitions)
|
||||
text = scrub_comments(text)
|
||||
|
||||
text = "<!-- Generated automatically - edit the templates! -->\n\n" + text
|
||||
|
||||
@ -140,9 +129,7 @@ def compose_general_page(relative_path):
|
||||
write_page(relative_path, text)
|
||||
|
||||
def list_general_pages():
|
||||
return filter(
|
||||
lambda s: not os.path.splitext(os.path.basename(s))[0].isupper(),
|
||||
glob.glob("*.md"))
|
||||
return glob.glob("*.md")
|
||||
|
||||
def process_threaded(directory):
|
||||
sources = glob.glob(os.path.join(directory, "*.md"))
|
||||
@ -156,7 +143,7 @@ def process_threaded(directory):
|
||||
|
||||
source_file = \
|
||||
os.path.splitext(os.path.basename(file))[0] + "." + CXX_EXTENSION
|
||||
source_link = "$repo/blob/$ref/example/" + source_file
|
||||
source_link = "$repo/blob/$version/example/" + source_file
|
||||
|
||||
definitions[directory + "_body"] = definitions["body"]
|
||||
definitions["body"] = templates[directory]
|
||||
@ -196,10 +183,6 @@ def generate_sitemap():
|
||||
for url in generated:
|
||||
text += " <url>\n"
|
||||
text += " <loc>%s</loc>\n" % url
|
||||
|
||||
if ".html" not in url:
|
||||
text += " <priority>1.0</priority>\n"
|
||||
|
||||
text += " </url>\n"
|
||||
|
||||
text += "</urlset>\n"
|
||||
@ -209,9 +192,6 @@ def generate_sitemap():
|
||||
def main():
|
||||
load_templates()
|
||||
|
||||
if not (len(sys.argv) >= 2 and sys.argv[1] == "--web"):
|
||||
templates["ga"] = ""
|
||||
|
||||
remove_output_directory()
|
||||
|
||||
process_threaded(TUTORIAL_DIRECTORY)
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 79 KiB |
214
doc/index.md
214
doc/index.md
@ -1,3 +1,9 @@
|
||||
Better Enums is a single header file that causes your compiler to generate
|
||||
*reflective* enum types. This makes it easy to translate between enums and
|
||||
strings, and much more.
|
||||
|
||||
Here's how to use a Better Enum:
|
||||
|
||||
<div class="splash">
|
||||
<pre class="left">enable
|
||||
|
||||
@ -5,7 +11,7 @@ declare
|
||||
|
||||
|
||||
parse
|
||||
format
|
||||
print
|
||||
|
||||
|
||||
count
|
||||
@ -13,7 +19,6 @@ iterate
|
||||
|
||||
|
||||
|
||||
|
||||
switch
|
||||
|
||||
|
||||
@ -24,25 +29,22 @@ switch
|
||||
safe cast
|
||||
|
||||
|
||||
during
|
||||
compilation
|
||||
</pre>
|
||||
<pre class="right"><em>#include <enum.h></em>
|
||||
at compile time</pre>
|
||||
<pre class="right"><em>#include</em> <<em>enum.h</em>>
|
||||
|
||||
<em>BETTER_ENUM(Channel, int, Red = 1, Green, Blue)</em>
|
||||
<em>ENUM</em>(<em>Channel</em>, <em>int</em>, <em>Red</em> = <em>1</em>, <em>Green</em>, <em>Blue</em>)
|
||||
|
||||
|
||||
Channel c = <em>Channel::_from_string("Red")</em>;
|
||||
const char *s = <em>c._to_string()</em>;
|
||||
|
||||
|
||||
size_t n = <em>Channel::_size()</em>;
|
||||
<em>for (Channel c : Channel::_values())</em> {
|
||||
run_some_function(c);
|
||||
}
|
||||
size_t n = <em>Channel::_size</em>;
|
||||
<em>for</em> (<em>Channel c</em> : <em>Channel::_values()</em>)
|
||||
run_some_function(<em>c</em>);
|
||||
|
||||
|
||||
<em>switch (c)</em> {
|
||||
<em>switch</em> (<em>c</em>) {
|
||||
<em>case Channel::Red</em>: // ...
|
||||
<em>case Channel::Green</em>: // ...
|
||||
<em>case Channel::Blue</em>: // ...
|
||||
@ -52,90 +54,17 @@ size_t n = <em>Channel::_size()</em>;
|
||||
Channel c = <em>Channel::_from_integral(3)</em>;
|
||||
|
||||
|
||||
<em>constexpr</em> Channel c =
|
||||
<em>Channel::_from_string("Blue")</em>;</pre>
|
||||
<em>constexpr</em> Channel c = <em>Channel::_from_string("Blue")</em>;</pre>
|
||||
</div>
|
||||
|
||||
<p class="splash-text">
|
||||
$be is a single, lightweight header file that makes your compiler generate
|
||||
<em>reflective</em> enum types.
|
||||
</p>
|
||||
|
||||
That means you can easily convert enums to and from strings,
|
||||
validate them, and loop over them. In $cxx11, you can do it all at
|
||||
compile time.
|
||||
|
||||
It's what built-in enums ought to support. Better Enums simply adds the missing
|
||||
features. And, it is based on the best known techniques, thoroughly tested,
|
||||
fast, portable, and documented exhaustively.
|
||||
|
||||
To use it, just include <code>enum.h</code> and begin the
|
||||
[tutorial](${prefix}tutorial/HelloWorld.html)!
|
||||
|
||||
<div class="hack"></div>
|
||||
|
||||
### Highlights
|
||||
### What do you get?
|
||||
|
||||
<ul class="blurbs">
|
||||
<li class="zero-mod-two zero-mod-three">
|
||||
<strong>Unobtrusive syntax</strong>
|
||||
<em>
|
||||
No ugly macros. Use initializers as with built-in <code>enums</code>.
|
||||
Internal members have underscores to avoid clashing with your constant
|
||||
names.
|
||||
</em>
|
||||
<li class="even">
|
||||
<strong>Uniform interface for $cxx98 and $cxx11</strong>
|
||||
<em>Scoped, sized, reflective enums for $cxx98.</em>
|
||||
</li>
|
||||
|
||||
<li class="one-mod-two one-mod-three">
|
||||
<strong>No external dependencies</strong>
|
||||
<em>
|
||||
Uses only standard $cxx. Installation is simple — just download
|
||||
<code>enum.h</code>. There are no objects or libraries to link with.
|
||||
</em>
|
||||
</li>
|
||||
|
||||
<li class="zero-mod-two two-mod-three">
|
||||
<strong>No generator program needed</strong>
|
||||
<em>
|
||||
Just include <code>enum.h</code>. It's a metaprogram executed by your
|
||||
compiler.
|
||||
</em>
|
||||
</li>
|
||||
|
||||
<li class="one-mod-two zero-mod-three">
|
||||
<strong>Plays nice with <code>switch</code></strong>
|
||||
<em>
|
||||
Use a Better Enum like a built-in <code>enum</code>, and still have the
|
||||
compiler do case checking.
|
||||
</em>
|
||||
</li>
|
||||
|
||||
<li class="zero-mod-two one-mod-three">
|
||||
<strong>Don't repeat yourself</strong>
|
||||
<em>
|
||||
No more unmaintanable maps or <code>switch</code> statements for
|
||||
converting enums to strings.
|
||||
</em>
|
||||
</li>
|
||||
|
||||
<li class="one-mod-two two-mod-three">
|
||||
<strong>Non-contiguous sequences</strong>
|
||||
<em>
|
||||
Iteration and counting are much easier to maintain than with an extra
|
||||
<code>Count</code> constant and assuming a dense range.
|
||||
</em>
|
||||
</li>
|
||||
|
||||
<li class="zero-mod-two zero-mod-three">
|
||||
<strong>Fast compilation</strong>
|
||||
<em>
|
||||
Much less impact on build time than even just including
|
||||
<code>iostream</code>. <code>enum.h</code> is only slightly more than 1000
|
||||
lines long.
|
||||
</em>
|
||||
</li>
|
||||
|
||||
<li class="one-mod-two one-mod-three">
|
||||
<li>
|
||||
<strong>Compile-time reflection</strong>
|
||||
<em>
|
||||
Have the compiler do additional enum processing using your own
|
||||
@ -143,23 +72,60 @@ To use it, just include <code>enum.h</code> and begin the
|
||||
</em>
|
||||
</li>
|
||||
|
||||
<li class="zero-mod-two two-mod-three">
|
||||
<strong>Uniform interface for $cxx98, $cxx11</strong>
|
||||
<li class="even">
|
||||
<strong>Non-contiguous sequences</strong>
|
||||
<em>
|
||||
Scoped, sized, reflective enums for $cxx98, and an easy upgrade
|
||||
path.
|
||||
Iteration and count much easier to maintain than with an extra "count"
|
||||
constant and making assumptions.
|
||||
</em>
|
||||
</li>
|
||||
<li>
|
||||
<strong>Plays nice with <code>switch</code></strong>
|
||||
<em>
|
||||
Use a Better Enum like a built-in <code>enum</code>, and still have the
|
||||
compiler do case checking.
|
||||
</em>
|
||||
</li>
|
||||
|
||||
<li class="one-mod-two zero-mod-three">
|
||||
<strong>Stream operators</strong>
|
||||
<li class="even">
|
||||
<strong>Unobtrusive syntax</strong>
|
||||
<em>
|
||||
Write enum names directly to <code>std::cout</code> or use
|
||||
<code>boost::lexical_cast</code>.
|
||||
No ugly macros. Use initializers just like with built-in
|
||||
<code>enums</code>. Generated members have underscores to avoid conflicts
|
||||
with your constant names.
|
||||
</em>
|
||||
</li>
|
||||
<li>
|
||||
<strong>Don't repeat yourself</strong>
|
||||
<em>
|
||||
No more unmaintanable maps or <code>switch</code> statements for
|
||||
converting enums to strings.
|
||||
</em>
|
||||
</li>
|
||||
|
||||
<li class="zero-mod-two one-mod-three">
|
||||
<li class="even">
|
||||
<strong>No build-time generator needed</strong>
|
||||
<em>
|
||||
Just include <code>enum.h</code>. It's a metaprogram executed by your
|
||||
compiler.
|
||||
</em>
|
||||
</li>
|
||||
<li>
|
||||
<strong>Fast compilation</strong>
|
||||
<em>
|
||||
Much less impact on build time than even just including
|
||||
<code>iostream</code>.
|
||||
</em>
|
||||
</li>
|
||||
|
||||
<li class="even">
|
||||
<strong>No external dependencies</strong>
|
||||
<em>
|
||||
Uses standard $cxx and supported on major compilers. Installation is
|
||||
simple — just download <code>enum.h</code>.
|
||||
</em>
|
||||
</li>
|
||||
<li>
|
||||
<strong>Free and open source</strong>
|
||||
<em>
|
||||
Released under the BSD license for use in any project, free or commercial.
|
||||
@ -169,18 +135,40 @@ To use it, just include <code>enum.h</code> and begin the
|
||||
|
||||
<div class="hack"></div>
|
||||
|
||||
### Documentation
|
||||
### It's what built-in enums ought to do.
|
||||
|
||||
The library notionally <em>extends</em> $cxx, adding oft-needed features.
|
||||
|
||||
<ul class="blurbs act">
|
||||
<li class="even">
|
||||
<strong>Download <a $download><code>enum.h</code></a></strong>
|
||||
<em>
|
||||
Current version: $version<br />
|
||||
To install, just add the file to your project.
|
||||
</em>
|
||||
</li>
|
||||
<li>
|
||||
<strong>Visit on <a href="$repo">GitHub</a></strong>
|
||||
<em>
|
||||
Follow development, report issues, and let me know if you find this
|
||||
library useful!
|
||||
</em>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="hack"></div>
|
||||
|
||||
### Resources
|
||||
|
||||
<ul class="blurbs resources">
|
||||
<li class="zero-mod-two zero-mod-three">
|
||||
<li class="even">
|
||||
<a id="Tutorial"></a>
|
||||
<strong>Tutorial</strong>
|
||||
<ol>
|
||||
$tutorial_toc
|
||||
</ol>
|
||||
</li>
|
||||
|
||||
<li class="one-mod-two one-mod-three">
|
||||
<li>
|
||||
<strong>Reference</strong>
|
||||
<ul>
|
||||
<li><a href="${prefix}ApiReference.html">API reference</a></li>
|
||||
@ -188,20 +176,12 @@ To use it, just include <code>enum.h</code> and begin the
|
||||
<li><a href="${prefix}OptInFeatures.html">Opt-in features</a></li>
|
||||
<li><a href="${prefix}ExtendingLimits.html">Extending limits</a></li>
|
||||
<li><a href="${prefix}Performance.html">Performance</a></li>
|
||||
<li>
|
||||
<a href="${prefix}DesignDecisionsFAQ.html">Design decisions FAQ</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://www.codeproject.com/Articles/1002895/Clean-Reflective-Enums-Enum-to-String-with-Nice-Sy">
|
||||
Implementation <span class="external">[CodeProject]</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="zero-mod-two two-mod-three">
|
||||
<li class="even">
|
||||
<a id="CompileTimeDemos"></a>
|
||||
<strong>Advanced</strong>
|
||||
<strong>Compile-time demos</strong>
|
||||
<ul>
|
||||
$demo_toc
|
||||
</ul>
|
||||
@ -212,8 +192,8 @@ To use it, just include <code>enum.h</code> and begin the
|
||||
|
||||
%% title = Clean reflective enums for C++
|
||||
|
||||
%% description = Reflective enums in a single header file, with clean syntax.
|
||||
The enums can be converted to string, iterated, and counted, at run time or
|
||||
as part of metaprogramming. Free and open source under the BSD license.
|
||||
%% description = Reflective enums for C++ with clean syntax, in a header-only
|
||||
library. Can be converted to strings, iterated, counted, and used for
|
||||
metaprogramming. Free under the BSD license.
|
||||
|
||||
%% class = index
|
||||
|
||||
1102
doc/mistune.py
1102
doc/mistune.py
File diff suppressed because it is too large
Load Diff
10
doc/sitemap.xml
Normal file
10
doc/sitemap.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<url>
|
||||
<loc>http://aantron.github.io/better-enums</loc>
|
||||
<priority>1.0</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>http://aantron.github.io/better-enums/api.html</loc>
|
||||
</url>
|
||||
</urlset>
|
||||
1
doc/template/cxx14.tmpl
vendored
1
doc/template/cxx14.tmpl
vendored
@ -1 +0,0 @@
|
||||
<span class="cpp">C++</span><span class="eleven">14</span>
|
||||
1
doc/template/cxx17.tmpl
vendored
1
doc/template/cxx17.tmpl
vendored
@ -1 +0,0 @@
|
||||
<span class="cpp">C++</span><span class="eleven">17</span>
|
||||
6
doc/template/demo.tmpl
vendored
6
doc/template/demo.tmpl
vendored
@ -1,7 +1,7 @@
|
||||
<p>
|
||||
This is an example of code you can write on top of Better Enums. It's a valid
|
||||
program — you can <a href="$source">download</a> it and try it out. The
|
||||
program is also part of the test suite.
|
||||
This page is an advanced demo showing the kind of compile-time code you can
|
||||
write on top of Better Enums. You can <a href="$source">download</a> it and
|
||||
try it out.
|
||||
</p>
|
||||
|
||||
$demo_body
|
||||
|
||||
2
doc/template/download.tmpl
vendored
2
doc/template/download.tmpl
vendored
@ -1,2 +1,2 @@
|
||||
href="https://raw.githubusercontent.com/aantron/better-enums/$ref/enum.h"
|
||||
href="https://raw.githubusercontent.com/aantron/better-enums/$version/enum.h"
|
||||
download
|
||||
5
doc/template/footer.tmpl
vendored
5
doc/template/footer.tmpl
vendored
@ -3,9 +3,8 @@
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
Copyright © 2015-2024 Anton Bachin. Released under the BSD 2-clause
|
||||
license. See
|
||||
<a href="https://github.com/aantron/better-enums/blob/$ref/doc/LICENSE">
|
||||
Copyright © 2015 Anton Bachin. Released under the BSD 2-clause license.
|
||||
See <a href="https://github.com/aantron/better-enums/blob/master/LICENSE">
|
||||
LICENSE</a>.
|
||||
<br />
|
||||
This page is part of the documentation for Better Enums $version.
|
||||
|
||||
10
doc/template/ga.tmpl
vendored
10
doc/template/ga.tmpl
vendored
@ -1,10 +0,0 @@
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-62962513-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
1
doc/template/ghfork.tmpl
vendored
1
doc/template/ghfork.tmpl
vendored
@ -1 +0,0 @@
|
||||
<iframe src="https://ghbtns.com/github-btn.html?user=aantron&repo=better-enums&type=fork&count=true" frameborder="0" scrolling="0" width="170px" height="20px" class="gh-button"></iframe>
|
||||
1
doc/template/ghstar.tmpl
vendored
1
doc/template/ghstar.tmpl
vendored
@ -1 +0,0 @@
|
||||
<iframe src="https://ghbtns.com/github-btn.html?user=aantron&repo=better-enums&type=star&count=true" frameborder="0" scrolling="0" width="170px" height="20px" class="gh-button"></iframe>
|
||||
1
doc/template/ghwatch.tmpl
vendored
1
doc/template/ghwatch.tmpl
vendored
@ -1 +0,0 @@
|
||||
<iframe src="https://ghbtns.com/github-btn.html?user=aantron&repo=better-enums&type=watch&count=true&v=2" frameborder="0" scrolling="0" height="20px" class="gh-watch gh-button"></iframe>
|
||||
20
doc/template/header.tmpl
vendored
20
doc/template/header.tmpl
vendored
@ -13,8 +13,6 @@
|
||||
|
||||
<link rel="stylesheet" href="${prefix}better-enums.css" />
|
||||
|
||||
$ga
|
||||
|
||||
</head>
|
||||
<body class="$class">
|
||||
|
||||
@ -25,6 +23,7 @@ $ga
|
||||
<a href="${prefix}index.html">Home</a>
|
||||
<a href="${prefix}tutorial/HelloWorld.html">Tutorial</a>
|
||||
<a href="${prefix}ApiReference.html">Reference</a>
|
||||
<a href="${prefix}Contact.html">Contact</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
@ -32,24 +31,11 @@ $ga
|
||||
|
||||
<header>
|
||||
<div class="container">
|
||||
<section>
|
||||
<div class="back">{}</div>
|
||||
|
||||
<h1><a href="${prefix}index.html">Better Enums</a></h1>
|
||||
<h2>Reflective compile-time enums for $cxx</h2>
|
||||
<h3>Open-source under the BSD license</h3>
|
||||
</section>
|
||||
|
||||
<section class="notes">
|
||||
<p>Version $version</p>
|
||||
<p>To install, just add <code>enum.h</code> to your project.</p>
|
||||
<p>
|
||||
Visit the GitHub repo for issues, feedback, and the latest development.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="buttons">
|
||||
<a $download>Download <code>enum.h</code></a>
|
||||
<a href="$repo">GitHub</a>
|
||||
</section>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
||||
1
doc/template/ref.tmpl
vendored
1
doc/template/ref.tmpl
vendored
@ -1 +0,0 @@
|
||||
0.11.3
|
||||
3
doc/template/tutorial.tmpl
vendored
3
doc/template/tutorial.tmpl
vendored
@ -1,7 +1,6 @@
|
||||
<p>
|
||||
Welcome to the Better Enums tutorials! The code in this tutorial forms a
|
||||
valid program, which you can <a href="$source">download</a> and play with. The
|
||||
program runs as part of the automated test suite.
|
||||
valid program, which you can <a href="$source">download</a> and play with.
|
||||
</p>
|
||||
|
||||
$tutorial_body
|
||||
|
||||
2
doc/template/version.tmpl
vendored
2
doc/template/version.tmpl
vendored
@ -1 +1 @@
|
||||
0.11.3
|
||||
0.9.0
|
||||
@ -50,7 +50,7 @@ def camel_case(text):
|
||||
components = re.split("[ -]+", text)
|
||||
components = map(lambda s: s.capitalize(), components)
|
||||
result = "".join(components)
|
||||
result = filter(lambda c: c not in ",!:-$()?", result)
|
||||
result = filter(lambda c: c not in ",!:-$()", result)
|
||||
return result
|
||||
|
||||
class HtmlRenderer(mistune.Renderer):
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
## Hello, World!
|
||||
|
||||
Download <a $download><code>enum.h</code></a>, then compile this program:
|
||||
Download <a $download><code>enum.h</code></a>, then build this program with it:
|
||||
|
||||
#include <iostream>
|
||||
<em>#include "enum.h"</em>
|
||||
|
||||
<em>BETTER_ENUM</em>(<em>Word</em>, <em>int</em>, <em>Hello</em>, <em>World</em>)
|
||||
<em>ENUM</em>(<em>Word</em>, <em>int</em>, <em>Hello</em>, <em>World</em>)
|
||||
|
||||
int main()
|
||||
{
|
||||
@ -20,5 +20,4 @@ Run it, and you should see the output "Hello, World!"
|
||||
|
||||
Congratulations, you have just created your first Better Enum!
|
||||
|
||||
%% description = Introductory Better Enums tutorial - a simple, but complete,
|
||||
Hello World program.
|
||||
%% description = Introductory Better Enums tutorial.
|
||||
|
||||
@ -7,7 +7,7 @@ Let's begin by including `enum.h` and declaring our enum:
|
||||
|
||||
<em>#include <enum.h></em>
|
||||
|
||||
<em>BETTER_ENUM</em>(<em>Channel</em>, <em>int</em>, <em>Cyan</em> = <em>1</em>, <em>Magenta</em>, <em>Yellow</em>, <em>Black</em>)
|
||||
<em>ENUM</em>(<em>Channel</em>, <em>int</em>, <em>Cyan</em> = <em>1</em>, <em>Magenta</em>, <em>Yellow</em>, <em>Black</em>)
|
||||
|
||||
We now have an `int`-sized enum with four constants.
|
||||
|
||||
@ -149,6 +149,4 @@ reference has a
|
||||
return 0;
|
||||
}
|
||||
|
||||
%% description = Better Enums conversion functions. Converting to string, from
|
||||
string, to int, from int, and validation, both case-sensitive and
|
||||
case-insensitive. Exception-throwing and non-throwing variants presented.
|
||||
%% description = Walkthrough of Better Enums conversion functions.
|
||||
|
||||
@ -6,12 +6,12 @@ example, this:
|
||||
#include <iostream>
|
||||
#include <enum.h>
|
||||
|
||||
<em>BETTER_ENUM(Channel, int, Red, Green = 2, Blue)</em>
|
||||
<em>ENUM(Channel, int, Red, Green = 2, Blue)</em>
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
<em>for</em> (<em>size_t index = 0</em>; <em>index < Channel::_size()</em>; <em>++index</em>) {
|
||||
<em>for</em> (<em>size_t index = 0</em>; <em>index < Channel::_size</em>; <em>++index</em>) {
|
||||
Channel channel = <em>Channel::_values()[index]</em>;
|
||||
std::cout << channel._to_integral() << " ";
|
||||
}
|
||||
@ -19,7 +19,7 @@ example, this:
|
||||
|
||||
will print "0 2 3". And this:
|
||||
|
||||
<em>for</em> (<em>size_t index = 0</em>; <em>index < Channel::_size()</em>; <em>++index</em>) {
|
||||
<em>for</em> (<em>size_t index = 0</em>; <em>index < Channel::_size</em>; <em>++index</em>) {
|
||||
const char *name = <em>Channel::_names()[index]</em>;
|
||||
std::cout << name << " ";
|
||||
}
|
||||
@ -46,5 +46,4 @@ If you are using $cxx11, you can have much nicer syntax:
|
||||
return 0;
|
||||
}
|
||||
|
||||
%% description = Using Better Enums to iterate over all the constants of an
|
||||
enum, as well as over its names. Also shows the same with C++11 for-each syntax.
|
||||
%% description = Iterating over all Better Enums constants.
|
||||
|
||||
@ -5,7 +5,7 @@ A Better Enum can be used directly in a `switch` statement:
|
||||
#include <iostream>
|
||||
<em>#include <enum.h></em>
|
||||
|
||||
<em>BETTER_ENUM(Channel, int, Red, Green, Blue)</em>
|
||||
<em>ENUM(Channel, int, Red, Green, Blue)</em>
|
||||
|
||||
int main()
|
||||
{
|
||||
@ -21,16 +21,10 @@ A Better Enum can be used directly in a `switch` statement:
|
||||
If you miss a case or add a redundant one, your compiler should be able to give
|
||||
you a warning — try it!
|
||||
|
||||
Note that on msvc, you may need to enable [warning C4062][C4062].
|
||||
|
||||
[C4062]: https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-4-c4062
|
||||
|
||||
---
|
||||
|
||||
std::cout << n << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
%% description = Better Enums can be used directly in switch statements like
|
||||
normal enums, making it possible for the compiler to check that all cases are
|
||||
listed, increasing the safety of your code.
|
||||
%% description = Usage in switch statements.
|
||||
|
||||
@ -1,77 +0,0 @@
|
||||
## Maps
|
||||
|
||||
It is possible to create `constexpr` bidirectional maps between Better Enums and
|
||||
any type. This is currently an experimental feature. Feedback is very much
|
||||
wanted, but please don't build any mission-critical code on top of this :)
|
||||
|
||||
The way it works is you give Better Enums a function — say,
|
||||
`const char* describe(Channel)`. The library enumerates it to make a map.
|
||||
|
||||
The reason for using a function is that a `switch` statement is, I believe, the
|
||||
only place where a compiler will check for exhaustiveness. If you forget to
|
||||
create a case for one of the enum's constants, the compiler can let you know.
|
||||
Obviously, a `switch` statement is not data, and needs to be inside a function.
|
||||
It can only be inside a `constexpr` function in $cxx14, so this feature is most
|
||||
natural in $cxx14. When you pass the function to Better Enums, the library can
|
||||
build up a lookup data structure at compile time.
|
||||
|
||||
Actually, right now, Better Enums doesn't quite do that — it enumerates
|
||||
the function *every* time you want to convert to an enum (but not *from* an
|
||||
enum). It simply does a linear scan every time. This is because I haven't yet
|
||||
found a data structure whose compile-time generation is fast enough for
|
||||
practical use.
|
||||
|
||||
---
|
||||
|
||||
#include <iostream>
|
||||
<em>#include</em> <<em>enum.h</em>>
|
||||
|
||||
<em>BETTER_ENUM</em>(<em>Channel</em>, <em>int</em>, <em>Red</em>, <em>Green</em>, <em>Blue</em>)
|
||||
|
||||
We will create a map from this function:
|
||||
|
||||
constexpr <em>const char* describe</em>(<em>Channel channel</em>)
|
||||
{
|
||||
switch(<em>channel</em>) {
|
||||
case <em>Channel::Red</em>: return <em>"the red channel"</em>;
|
||||
case <em>Channel::Green</em>: return <em>"the green channel"</em>;
|
||||
case <em>Channel::Blue</em>: return <em>"the blue channel"</em>;
|
||||
}
|
||||
|
||||
return "needed for gcc 5";
|
||||
}
|
||||
|
||||
Here is the map. The actual type is `better_enums::map<Channel, const char*>`.
|
||||
|
||||
constexpr auto <em>descriptions</em> = <em>better_enums::make_map</em>(<em>describe</em>);
|
||||
|
||||
And the usage:
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout << <em>descriptions[Channel::Red]</em> << std::endl;
|
||||
|
||||
std::cout << <em>descriptions</em>.<em>from_enum</em>(<em>Channel::Red</em>) << std::endl;
|
||||
std::cout << <em>descriptions</em>.<em>to_enum</em>(<em>"the green channel"</em>) << std::endl;
|
||||
|
||||
auto <em>not_a_literal</em> = <em>std::string</em>(<em>"the blue channel"</em>);
|
||||
std::cout << <em>descriptions</em>.<em>to_enum</em>(<em>not_a_literal</em>.<em>c_str()</em>) << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
---
|
||||
|
||||
`make_map` above produces a value of type `better_enums::map<E, T>`. The full
|
||||
signature of the template `better_enums::map` is
|
||||
|
||||
~~~comment
|
||||
<em>template <typename Enum, typename T, typename Compare = map_compare<T>></em>
|
||||
~~~
|
||||
|
||||
`Compare` has to be a class with a static member function
|
||||
`bool less(const T&, const T&)`. The default implementation
|
||||
`better_enums::map_compare` simply applies `operator <`, except when `T` is
|
||||
`const char*` or `const wchar_t*`. In that case, it does lexicographic comparison.
|
||||
|
||||
%% description = Mapping enums to arbitrary types and vice versa.
|
||||
@ -3,12 +3,6 @@
|
||||
This tutorial shows some of the safety features of Better Enums: scope, how to
|
||||
control conversions, and the lack of a default constructor.
|
||||
|
||||
On balance, Better Enums are in one way less type-safe than enum class, and in
|
||||
another way more type-safe. The first difference in safety is the presence of
|
||||
implicit conversion to integral types. The second difference is the lack of a
|
||||
default constructor. Both of these can be toggled, so you can make Better Enums
|
||||
strictly safer than enum class, or just as safe.
|
||||
|
||||
$internal_toc
|
||||
|
||||
### Scope
|
||||
@ -18,7 +12,7 @@ You have probably noticed by now that Better Enums are scoped: when you declare
|
||||
#include <cassert>
|
||||
<em>#include <enum.h></em>
|
||||
|
||||
<em>BETTER_ENUM</em>(<em>Channel</em>, <em>int</em>, <em>Red</em> = <em>1</em>, <em>Green</em>, <em>Blue</em>)
|
||||
<em>ENUM</em>(<em>Channel</em>, <em>int</em>, <em>Red</em> = <em>1</em>, <em>Green</em>, <em>Blue</em>)
|
||||
|
||||
you don't get names such as `Red` in the global namespace. Instead, you get
|
||||
`Channel`, and `Red` is accessible as `Channel::Red`. This is no big deal in
|
||||
@ -26,7 +20,7 @@ $cxx11, which has `enum class`. In $cxx98, however, this typically requires
|
||||
effort. Better Enums brings scope uniformly to both variants. So, despite the
|
||||
above declaration, you can safely declare
|
||||
|
||||
<em>BETTER_ENUM</em>(<em>Node</em>, <em>char</em>, <em>Red</em>, <em>Black</em>)
|
||||
<em>ENUM</em>(<em>Node</em>, <em>char</em>, <em>Red</em>, <em>Black</em>)
|
||||
|
||||
and everything will work as expected.
|
||||
|
||||
@ -53,27 +47,33 @@ will not compile:
|
||||
The reason this is not enabled by default is explained in the reference page on
|
||||
[strict conversions](${prefix}OptInFeatures.html#StrictConversions).
|
||||
|
||||
You can conveniently define the macro on your compiler's command line, or by
|
||||
creating a little header file that defines it, and then includes
|
||||
<code>enum.h</code>. You can then include this new header file in your project
|
||||
everywhere where you would have included <code>enum.h</code>.
|
||||
|
||||
### Default constructor
|
||||
|
||||
Better Enums generate without a default constructor. The purpose is to support
|
||||
the convention where if a Better Enum exists, then it has a valid value. So, if
|
||||
you uncomment this code, the program won't compile:
|
||||
Better Enums don't have a default constructor, for three reasons.
|
||||
|
||||
- Better Enums is a library that can't know what your application would like
|
||||
the default value to be for each enum, or whether you even want one.
|
||||
- I chose not to leave the default value undefined, because the idea is to
|
||||
encourage the convention that whenever a Better Enum exists, it has a valid
|
||||
value. This is borrowed from typed functional programming.
|
||||
- Better Enums is still under development, and this option is the most
|
||||
future-proof.
|
||||
|
||||
So, if you uncomment this code, the file won't compile:
|
||||
|
||||
~~~comment
|
||||
Channel channel;
|
||||
~~~
|
||||
|
||||
If this is too strict for your project, you can relax it as described
|
||||
[here](${prefix}OptInFeatures.html#DefaultConstructors).
|
||||
This may be too strict, and I may relax it in the future. In the meantime, the
|
||||
solution sketched in the [special values demo](${prefix}demo/SpecialValues.html)
|
||||
can replace default constructors for some purposes, and in a more flexible way.
|
||||
I may eventually have the default constructor calling a template function like
|
||||
the one in that demo.
|
||||
|
||||
---
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
%% description = Better Enums type safety features and limitations.
|
||||
%% description = Type safety features and limitations.
|
||||
@ -1,34 +0,0 @@
|
||||
## Stream operators
|
||||
|
||||
These work *almost* as you'd expect. First, make sure you include `iostream`
|
||||
before `enum.h` in any translation unit in which you intend to use the
|
||||
operators:
|
||||
|
||||
#include <iostream>
|
||||
#include <enum.h>
|
||||
|
||||
<em>BETTER_ENUM(Channel, int, Red, Green, Blue)</em>
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout << <em>+Channel::Red</em> << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
The thing to watch for is the `+`: without it, `Channel::Red` is a value of type
|
||||
`Channel::_enumerated`, a $cxx98 enum type, so writing that to `cout` will
|
||||
output an integer. `+Channel::Red`, however, is a value of type `Channel`, and
|
||||
writing *that* instead will output the string `"Red"`.
|
||||
|
||||
Input is also supported:
|
||||
|
||||
~~~comment
|
||||
Channel channel = Channel::Blue;
|
||||
std::cin >> channel; // Expects input such as "Green".
|
||||
~~~
|
||||
|
||||
---
|
||||
|
||||
Only `char` streams are supported for the time being.
|
||||
|
||||
%% description = Using Better Enums with stream input and output operators.
|
||||
@ -7,7 +7,7 @@ will declare a more unusual enum than the ones we have seen.
|
||||
#include <iostream>
|
||||
<em>#include <enum.h></em>
|
||||
|
||||
<em>BETTER_ENUM</em>(<em>ContentType</em>, <em>short</em>,
|
||||
<em>ENUM</em>(<em>ContentType</em>, <em>short</em>,
|
||||
<em>CompressedVideo</em> = <em>5</em>, <em>PCM</em> = <em>8</em>, <em>Subtitles</em> = <em>17</em>, <em>Comment</em> = <em>44</em>)
|
||||
|
||||
This is for a hypothetical multimedia container file format. Perhaps the files
|
||||
@ -80,5 +80,4 @@ types containg enums. The enums will behave as expected.
|
||||
compatible with $cxx98, where those names aren't available in a portable
|
||||
manner.
|
||||
|
||||
%% description = The underlying memory representation of a Better Enum,
|
||||
including size and alignment.
|
||||
%% description = Underlying representation.
|
||||
@ -15,7 +15,7 @@ get an idea of what can be done. Here, you will see the basics.
|
||||
|
||||
<em>#include <enum.h></em>
|
||||
|
||||
<em>BETTER_ENUM</em>(<em>Channel</em>, <em>int</em>, <em>Red</em> = <em>1</em>, <em>Green</em> = <em>2</em>, <em>Blue</em> = <em>3</em>)
|
||||
<em>ENUM</em>(<em>Channel</em>, <em>int</em>, <em>Red</em> = <em>1</em>, <em>Green</em> = <em>2</em>, <em>Blue</em> = <em>3</em>)
|
||||
|
||||
<em>constexpr</em> Channel channel = <em>Channel::_from_integral(2)</em>;
|
||||
<em>constexpr</em> int value = <em>channel._to_integral()</em>;
|
||||
@ -48,5 +48,4 @@ You can also do things such as:
|
||||
Which prints "5", the length of "Green". That 5 was also computed during
|
||||
compilation.
|
||||
|
||||
%% description = Better Enums can be used entirely at compile time in C++11. All
|
||||
conversion functions are available for constexpr functions or templates.
|
||||
%% description = Introduction to compile-time conversions.
|
||||
@ -2,12 +2,12 @@
|
||||
|
||||
// Hello, World!
|
||||
//
|
||||
// Download enum.h, then compile this program:
|
||||
// Download enum.h, then build this program with it:
|
||||
|
||||
#include <iostream>
|
||||
#include "enum.h"
|
||||
|
||||
BETTER_ENUM(Word, int, Hello, World)
|
||||
ENUM(Word, int, Hello, World)
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
@ -44,10 +44,10 @@ constexpr Enum invalid_impl<Enum>() { return Enum::Value; }
|
||||
|
||||
// Now, we can declare enums like these:
|
||||
|
||||
BETTER_ENUM(Channel, int, Red, Green, Blue, Invalid)
|
||||
ENUM(Channel, int, Red, Green, Blue, Invalid)
|
||||
// Invalid is the invalid value by default
|
||||
|
||||
BETTER_ENUM(Compression, int, Undefined, None, Huffman)
|
||||
ENUM(Compression, int, Undefined, None, Huffman)
|
||||
OVERRIDE_INVALID(Compression, Undefined)
|
||||
|
||||
// and use them:
|
||||
@ -69,7 +69,7 @@ template <typename Enum>
|
||||
constexpr Enum default_impl()
|
||||
{
|
||||
return
|
||||
Enum::_size() < 2 ?
|
||||
Enum::_size < 2 ?
|
||||
throw std::logic_error("enum has no valid constants") :
|
||||
Enum::_values()[0] == invalid_impl<Enum>() ?
|
||||
Enum::_values()[1] :
|
||||
@ -98,7 +98,7 @@ static_assert(default_impl<Compression>() == +Compression::None, "");
|
||||
|
||||
// And, if you do
|
||||
|
||||
BETTER_ENUM(Answer, int, Yes, No, Invalid)
|
||||
ENUM(Answer, int, Yes, No, Invalid)
|
||||
// OVERRIDE_DEFAULT(Answer, Invalid)
|
||||
|
||||
// you will get a helpful compile-time error saying Answer: default cannot equal
|
||||
|
||||
@ -17,7 +17,7 @@ template <typename Enum>
|
||||
constexpr Enum max_loop(Enum accumulator, size_t index)
|
||||
{
|
||||
return
|
||||
index >= Enum::_size() ? accumulator :
|
||||
index >= Enum::_size ? accumulator :
|
||||
Enum::_values()[index] > accumulator ?
|
||||
max_loop<Enum>(Enum::_values()[index], index + 1) :
|
||||
max_loop<Enum>(accumulator, index + 1);
|
||||
@ -38,7 +38,7 @@ using EnumSet = std::bitset<max<Enum>()._to_integral() + 1>;
|
||||
// declared. We just declare enums, and the numeric values of their constants
|
||||
// will be bit indices. The rest is straightforward.
|
||||
|
||||
BETTER_ENUM(EFLAGS, int,
|
||||
ENUM(EFLAGS, int,
|
||||
Carry, Parity = 2, Adjust = 4, Zero, Sign, Trap, Interrupt, Direction,
|
||||
Overflow, NestedTask = 14, Resume = 16, V8086, AlignmentCheck,
|
||||
CPUIDPresent = 21)
|
||||
@ -10,7 +10,7 @@
|
||||
// Ok, so it's not really a quine, because we won't be writing all the code
|
||||
// needed to generate the definition to the buffer as well. And, there are
|
||||
// better ways to dump the definition than shown here. You could simply define a
|
||||
// macro that expands to an BETTER_ENUM declaration and also stringizes it.
|
||||
// macro that expands to an ENUM declaration and also stringizes it.
|
||||
//
|
||||
// But that's not the point here. The point of this page is to show some of the
|
||||
// reflective capabilities of Better Enums, so you can adapt them for cases
|
||||
@ -34,8 +34,8 @@
|
||||
|
||||
// Now, let's declare some enums to dump later:
|
||||
|
||||
BETTER_ENUM(Channel, int, Red, Green, Blue)
|
||||
BETTER_ENUM(Depth, int, TrueColor = 1, HighColor = 0)
|
||||
ENUM(Channel, int, Red, Green, Blue)
|
||||
ENUM(Depth, int, TrueColor = 1, HighColor = 0)
|
||||
|
||||
|
||||
|
||||
@ -79,7 +79,7 @@ template <typename Enum>
|
||||
constexpr size_t constants_length(size_t index = 0, size_t accumulator = 0)
|
||||
{
|
||||
return
|
||||
index >= Enum::_size() ? accumulator :
|
||||
index >= Enum::_size ? accumulator :
|
||||
constants_length<Enum>(
|
||||
index + 1, accumulator
|
||||
+ string_length(", ")
|
||||
@ -99,7 +99,7 @@ template <typename Enum>
|
||||
constexpr size_t declaration_length()
|
||||
{
|
||||
return
|
||||
string_length("BETTER_ENUM(")
|
||||
string_length("ENUM(")
|
||||
+ string_length(Enum::_name())
|
||||
+ string_length(", int")
|
||||
+ constants_length<Enum>()
|
||||
@ -127,7 +127,7 @@ size_t format(char *buffer)
|
||||
{
|
||||
size_t offset = 0;
|
||||
|
||||
offset += std::sprintf(buffer, "BETTER_ENUM(%s, int", Enum::_name());
|
||||
offset += std::sprintf(buffer, "ENUM(%s, int", Enum::_name());
|
||||
|
||||
for (Enum value : Enum::_values()) {
|
||||
offset +=
|
||||
@ -163,5 +163,5 @@ int main()
|
||||
|
||||
// It prints:
|
||||
//
|
||||
// BETTER_ENUM(Channel, int, Red = 0, Green = 1, Blue = 2)
|
||||
// BETTER_ENUM(Depth, int, TrueColor = 1, HighColor = 0)
|
||||
// ENUM(Channel, int, Red = 0, Green = 1, Blue = 2)
|
||||
// ENUM(Depth, int, TrueColor = 1, HighColor = 0)
|
||||
@ -1,152 +0,0 @@
|
||||
// This file was generated automatically.
|
||||
|
||||
// C++17 reflection proposal
|
||||
//
|
||||
// You can try this demo live online.
|
||||
//
|
||||
// Better Enums can be used to implement the enums portion of the C++17
|
||||
// reflection proposal N4428 in C++11. N4428 proposes the following traits
|
||||
// interface:
|
||||
//
|
||||
// namespace std {
|
||||
//
|
||||
// template <typename E>
|
||||
// struct enum_traits {
|
||||
// struct enumerators {
|
||||
// constexpr static size_t size;
|
||||
//
|
||||
// template <size_t I>
|
||||
// struct get {
|
||||
// constexpr string_literal identifier;
|
||||
// constexpr static E value;
|
||||
// };
|
||||
// };
|
||||
// };
|
||||
//
|
||||
// }
|
||||
//
|
||||
// So, the basic usage would be:
|
||||
//
|
||||
// enum class Foo {A, B, C};
|
||||
//
|
||||
// constexpr size_t size =
|
||||
// std::enum_traits<Foo>::enumerators::size;
|
||||
//
|
||||
// constexpr Foo value_0 =
|
||||
// std::enum_traits<Foo>::enumerators::get<0>::value;
|
||||
//
|
||||
// constexpr string_literal name_1 =
|
||||
// std::enum_traits<Foo>::enumerators::get<1>::identifier;
|
||||
//
|
||||
// Resulting in the values 3, Foo::A, and "B", respectively.
|
||||
|
||||
// The interface is implemented in the optional header file
|
||||
// extra/better-enums/n4428.h. There is a necessary difference: the interface is
|
||||
// only available for enums declared through the BETTER_ENUM macro. This is
|
||||
// because the macro is what generates the information necessary for reflection.
|
||||
//
|
||||
// Demo
|
||||
//
|
||||
// So, with that out of the way, we can do a little test. Let's assume that
|
||||
// extra/ has been added as a directory to search for include files.
|
||||
|
||||
#ifndef BETTER_ENUMS_CONSTEXPR_TO_STRING
|
||||
#define BETTER_ENUMS_CONSTEXPR_TO_STRING
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <enum.h>
|
||||
#include <better-enums/n4428.h>
|
||||
|
||||
|
||||
// Let's declare an enum:
|
||||
|
||||
BETTER_ENUM(Channel, char, Red = 1, Green, Blue)
|
||||
|
||||
// ...and try N4428:
|
||||
|
||||
constexpr std::size_t size =
|
||||
std::enum_traits<Channel>::enumerators::size;
|
||||
|
||||
constexpr Channel value_0 =
|
||||
std::enum_traits<Channel>::enumerators::get<0>::value;
|
||||
|
||||
constexpr Channel value_1 =
|
||||
std::enum_traits<Channel>::enumerators::get<1>::value;
|
||||
|
||||
constexpr const char *identifier_2 =
|
||||
std::enum_traits<Channel>::enumerators::get<2>::identifier;
|
||||
|
||||
// ...and check the results:
|
||||
|
||||
static_assert(size == 3, "");
|
||||
|
||||
static_assert(value_0 == +Channel::Red, "");
|
||||
static_assert(value_1 == +Channel::Green, "");
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout << identifier_2 << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// That prints Blue, as you would expect.
|
||||
//
|
||||
// Quirk
|
||||
//
|
||||
// The reason for the #define in the code above is that there is one quirk: the
|
||||
// interface above is available only for Better Enums for which compile-time
|
||||
// name trimming is enabled - those declared when
|
||||
// BETTER_ENUMS_CONSTEXPR_TO_STRING was defined, or declared with the SLOW_ENUM
|
||||
// variant of BETTER_ENUM. As mentioned on the linked page, the reason
|
||||
// compile-time name trimming is not the default is that, while still pretty
|
||||
// fast, it is four times slower than program-startup-time name trimming. The
|
||||
// latter is the default.
|
||||
//
|
||||
// Despite the above, a variation on the interface is available for enums
|
||||
// without compile-time name trimming:
|
||||
//
|
||||
// namespace std {
|
||||
//
|
||||
// template <typename E>
|
||||
// struct enum_traits {
|
||||
// struct enumerators {
|
||||
// constexpr static size_t size;
|
||||
//
|
||||
// template <size_t I>
|
||||
// struct get {
|
||||
// constexpr const char *identifier;
|
||||
// constexpr static E value;
|
||||
// };
|
||||
//
|
||||
// // For enums without compile-time name trimming.
|
||||
// template <size_t I>
|
||||
// struct get_alt {
|
||||
// static const char* identifier();
|
||||
// constexpr static E value;
|
||||
// };
|
||||
// };
|
||||
// };
|
||||
//
|
||||
// }
|
||||
//
|
||||
// As you can see, the difference is that identifier is a non-constexpr
|
||||
// function, and you have to access it through get_alt<I>.
|
||||
//
|
||||
// // Without compile-time name trimming.
|
||||
// BETTER_ENUM(Depth, int, HighColor, TrueColor)
|
||||
//
|
||||
// int main()
|
||||
// {
|
||||
// std::cout
|
||||
// << std::enum_traits<Depth>::enumerators::get_alt<1>::identifier()
|
||||
// << std::endl;
|
||||
//
|
||||
// return 0;
|
||||
// }
|
||||
//
|
||||
// The future
|
||||
//
|
||||
// N4428 is the fourth in a series of revisions: N3815, N4027, N4113, N4428. If
|
||||
// there are more revisions that change the proposal for enums, I will try to
|
||||
// implement those as well.
|
||||
@ -9,7 +9,7 @@
|
||||
|
||||
#include <enum.h>
|
||||
|
||||
BETTER_ENUM(Channel, int, Cyan = 1, Magenta, Yellow, Black)
|
||||
ENUM(Channel, int, Cyan = 1, Magenta, Yellow, Black)
|
||||
|
||||
// We now have an int-sized enum with four constants.
|
||||
//
|
||||
|
||||
@ -8,12 +8,12 @@
|
||||
#include <iostream>
|
||||
#include <enum.h>
|
||||
|
||||
BETTER_ENUM(Channel, int, Red, Green = 2, Blue)
|
||||
ENUM(Channel, int, Red, Green = 2, Blue)
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
for (size_t index = 0; index < Channel::_size(); ++index) {
|
||||
for (size_t index = 0; index < Channel::_size; ++index) {
|
||||
Channel channel = Channel::_values()[index];
|
||||
std::cout << channel._to_integral() << " ";
|
||||
}
|
||||
@ -21,7 +21,7 @@ int main()
|
||||
|
||||
// will print "0 2 3". And this:
|
||||
|
||||
for (size_t index = 0; index < Channel::_size(); ++index) {
|
||||
for (size_t index = 0; index < Channel::_size; ++index) {
|
||||
const char *name = Channel::_names()[index];
|
||||
std::cout << name << " ";
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
#include <iostream>
|
||||
#include <enum.h>
|
||||
|
||||
BETTER_ENUM(Channel, int, Red, Green, Blue)
|
||||
ENUM(Channel, int, Red, Green, Blue)
|
||||
|
||||
int main()
|
||||
{
|
||||
@ -22,8 +22,6 @@ int main()
|
||||
|
||||
// If you miss a case or add a redundant one, your compiler should be able to
|
||||
// give you a warning - try it!
|
||||
//
|
||||
// Note that on msvc, you may need to enable warning C4062.
|
||||
|
||||
|
||||
std::cout << n << std::endl;
|
||||
|
||||
@ -1,74 +0,0 @@
|
||||
// This file was generated automatically.
|
||||
|
||||
// Maps
|
||||
//
|
||||
// It is possible to create constexpr bidirectional maps between Better Enums
|
||||
// and any type. This is currently an experimental feature. Feedback is very
|
||||
// much wanted, but please don't build any mission-critical code on top of this
|
||||
// :)
|
||||
//
|
||||
// The way it works is you give Better Enums a function - say, const char*
|
||||
// describe(Channel). The library enumerates it to make a map.
|
||||
//
|
||||
// The reason for using a function is that a switch statement is, I believe, the
|
||||
// only place where a compiler will check for exhaustiveness. If you forget to
|
||||
// create a case for one of the enum's constants, the compiler can let you know.
|
||||
// Obviously, a switch statement is not data, and needs to be inside a function.
|
||||
// It can only be inside a constexpr function in C++14, so this feature is most
|
||||
// natural in C++14. When you pass the function to Better Enums, the library can
|
||||
// build up a lookup data structure at compile time.
|
||||
//
|
||||
// Actually, right now, Better Enums doesn't quite do that - it enumerates the
|
||||
// function every time you want to convert to an enum (but not from an enum). It
|
||||
// simply does a linear scan every time. This is because I haven't yet found a
|
||||
// data structure whose compile-time generation is fast enough for practical
|
||||
// use.
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <enum.h>
|
||||
|
||||
BETTER_ENUM(Channel, int, Red, Green, Blue)
|
||||
|
||||
// We will create a map from this function:
|
||||
|
||||
constexpr const char* describe(Channel channel)
|
||||
{
|
||||
switch(channel) {
|
||||
case Channel::Red: return "the red channel";
|
||||
case Channel::Green: return "the green channel";
|
||||
case Channel::Blue: return "the blue channel";
|
||||
}
|
||||
|
||||
return "needed for gcc 5";
|
||||
}
|
||||
|
||||
// Here is the map. The actual type is better_enums::map<Channel, const char*>.
|
||||
|
||||
constexpr auto descriptions = better_enums::make_map(describe);
|
||||
|
||||
// And the usage:
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout << descriptions[Channel::Red] << std::endl;
|
||||
|
||||
std::cout << descriptions.from_enum(Channel::Red) << std::endl;
|
||||
std::cout << descriptions.to_enum("the green channel") << std::endl;
|
||||
|
||||
auto not_a_literal = std::string("the blue channel");
|
||||
std::cout << descriptions.to_enum(not_a_literal.c_str()) << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// make_map above produces a value of type better_enums::map<E, T>. The full
|
||||
// signature of the template better_enums::map is
|
||||
//
|
||||
// template <typename Enum, typename T, typename Compare = map_compare<T>>
|
||||
//
|
||||
// Compare has to be a class with a static member function bool less(const T&,
|
||||
// const T&). The default implementation better_enums::map_compare simply
|
||||
// applies operator <, except when T is const char*. In that case, it does
|
||||
// lexicographic comparison.
|
||||
@ -5,12 +5,6 @@
|
||||
// This tutorial shows some of the safety features of Better Enums: scope, how
|
||||
// to control conversions, and the lack of a default constructor.
|
||||
//
|
||||
// On balance, Better Enums are in one way less type-safe than enum class, and
|
||||
// in another way more type-safe. The first difference in safety is the presence
|
||||
// of implicit conversion to integral types. The second difference is the lack
|
||||
// of a default constructor. Both of these can be toggled, so you can make
|
||||
// Better Enums strictly safer than enum class, or just as safe.
|
||||
//
|
||||
// Scope
|
||||
//
|
||||
// You have probably noticed by now that Better Enums are scoped: when you
|
||||
@ -19,7 +13,7 @@
|
||||
#include <cassert>
|
||||
#include <enum.h>
|
||||
|
||||
BETTER_ENUM(Channel, int, Red = 1, Green, Blue)
|
||||
ENUM(Channel, int, Red = 1, Green, Blue)
|
||||
|
||||
// you don't get names such as Red in the global namespace. Instead, you get
|
||||
// Channel, and Red is accessible as Channel::Red. This is no big deal in C++11,
|
||||
@ -27,7 +21,7 @@ BETTER_ENUM(Channel, int, Red = 1, Green, Blue)
|
||||
// Better Enums brings scope uniformly to both variants. So, despite the above
|
||||
// declaration, you can safely declare
|
||||
|
||||
BETTER_ENUM(Node, char, Red, Black)
|
||||
ENUM(Node, char, Red, Black)
|
||||
|
||||
// and everything will work as expected.
|
||||
|
||||
@ -51,20 +45,28 @@ int main()
|
||||
// The reason this is not enabled by default is explained in the reference page
|
||||
// on strict conversions.
|
||||
//
|
||||
// You can conveniently define the macro on your compiler's command line, or by
|
||||
// creating a little header file that defines it, and then includes enum.h. You
|
||||
// can then include this new header file in your project everywhere where you
|
||||
// would have included enum.h.
|
||||
//
|
||||
// Default constructor
|
||||
//
|
||||
// Better Enums generate without a default constructor. The purpose is to
|
||||
// support the convention where if a Better Enum exists, then it has a valid
|
||||
// value. So, if you uncomment this code, the program won't compile:
|
||||
// Better Enums don't have a default constructor, for three reasons.
|
||||
//
|
||||
// 1. Better Enums is a library that can't know what your application would
|
||||
// like the default value to be for each enum, or whether you even want
|
||||
// one.
|
||||
// 2. I chose not to leave the default value undefined, because the idea is to
|
||||
// encourage the convention that whenever a Better Enum exists, it has a
|
||||
// valid value. This is borrowed from typed functional programming.
|
||||
// 3. Better Enums is still under development, and this option is the most
|
||||
// future-proof.
|
||||
//
|
||||
// So, if you uncomment this code, the file won't compile:
|
||||
//
|
||||
// Channel channel;
|
||||
//
|
||||
// If this is too strict for your project, you can relax it as described here.
|
||||
// This may be too strict, and I may relax it in the future. In the meantime,
|
||||
// the solution sketched in the special values demo can replace default
|
||||
// constructors for some purposes, and in a more flexible way. I may eventually
|
||||
// have the default constructor calling a template function like the one in that
|
||||
// demo.
|
||||
|
||||
|
||||
return 0;
|
||||
@ -1,30 +0,0 @@
|
||||
// This file was generated automatically.
|
||||
|
||||
// Stream operators
|
||||
//
|
||||
// These work almost as you'd expect. First, make sure you include iostream
|
||||
// before enum.h in any translation unit in which you intend to use the
|
||||
// operators:
|
||||
|
||||
#include <iostream>
|
||||
#include <enum.h>
|
||||
|
||||
BETTER_ENUM(Channel, int, Red, Green, Blue)
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout << +Channel::Red << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The thing to watch for is the +: without it, Channel::Red is a value of type
|
||||
// Channel::_enumerated, a C++98 enum type, so writing that to cout will output
|
||||
// an integer. +Channel::Red, however, is a value of type Channel, and writing
|
||||
// that instead will output the string "Red".
|
||||
//
|
||||
// Input is also supported:
|
||||
//
|
||||
// Channel channel = Channel::Blue;
|
||||
// std::cin >> channel; // Expects input such as "Green".
|
||||
|
||||
// Only char streams are supported for the time being.
|
||||
@ -9,7 +9,7 @@
|
||||
#include <iostream>
|
||||
#include <enum.h>
|
||||
|
||||
BETTER_ENUM(ContentType, short,
|
||||
ENUM(ContentType, short,
|
||||
CompressedVideo = 5, PCM = 8, Subtitles = 17, Comment = 44)
|
||||
|
||||
// This is for a hypothetical multimedia container file format. Perhaps the
|
||||
@ -17,7 +17,7 @@
|
||||
|
||||
#include <enum.h>
|
||||
|
||||
BETTER_ENUM(Channel, int, Red = 1, Green = 2, Blue = 3)
|
||||
ENUM(Channel, int, Red = 1, Green = 2, Blue = 3)
|
||||
|
||||
constexpr Channel channel = Channel::_from_integral(2);
|
||||
constexpr int value = channel._to_integral();
|
||||
@ -3,7 +3,7 @@ CXX := c++
|
||||
endif
|
||||
|
||||
ifndef CXXFLAGS
|
||||
CXXFLAGS := -std=c++11 -Wall -I .. -I../extra -o
|
||||
CXXFLAGS := -std=c++11 -Wall -I .. -o
|
||||
endif
|
||||
|
||||
SOURCES := $(wildcard *.cc)
|
||||
|
||||
@ -1,52 +0,0 @@
|
||||
// This file is part of Better Enums, released under the BSD 2-clause license.
|
||||
// See doc/LICENSE for details, or visit http://github.com/aantron/better-enums.
|
||||
|
||||
// This file provides an implementation of the enum reflection interface
|
||||
// proposed in
|
||||
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4428.pdf
|
||||
// on top of Better Enums.
|
||||
|
||||
// See further discussion and a demonstration of usage at
|
||||
// example/107-c++17-reflection.cc, or visit:
|
||||
// http://aantron.github.io/better-enums/demo/C++17ReflectionProposal.html
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef BETTER_ENUMS_N4428_H
|
||||
#define BETTER_ENUMS_N4428_H
|
||||
|
||||
|
||||
|
||||
namespace std {
|
||||
|
||||
template <typename Enum>
|
||||
struct enum_traits {
|
||||
struct enumerators {
|
||||
constexpr static const size_t size = Enum::_size();
|
||||
|
||||
template <size_t Index>
|
||||
struct get {
|
||||
constexpr static Enum value = Enum::_values()[Index];
|
||||
constexpr static const char *identifier = Enum::_names()[Index];
|
||||
};
|
||||
|
||||
// The above declarations implement N4428 (except for const char*
|
||||
// instead of string_literal). The alternative get below is needed for
|
||||
// Better Enums that weren't generated with compile-time name trimming,
|
||||
// i.e. without BETTER_ENUMS_CONSTEXPR_TO_STRING declared and not
|
||||
// through the SLOW_ENUM macro. That is currently the default for
|
||||
// Better Enums, since compile-time name trimming is pretty slow, so you
|
||||
// would want to use get_alt instead of get.
|
||||
template <size_t Index>
|
||||
struct get_alt {
|
||||
constexpr static Enum value = Enum::_values()[Index];
|
||||
static const char* identifier() { return Enum::_names()[Index]; };
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif // #ifndef BETTER_ENUMS_N4428_H
|
||||
@ -3,19 +3,18 @@
|
||||
# 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 _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.
|
||||
#
|
||||
# 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.
|
||||
# _ENUM_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_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).
|
||||
# _ENUM_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
|
||||
@ -29,7 +28,7 @@
|
||||
# 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.
|
||||
# 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.
|
||||
|
||||
@ -67,38 +66,35 @@ def generate(stream, constants, length, script):
|
||||
print >> stream, ''
|
||||
print >> stream, '#pragma once'
|
||||
print >> stream, ''
|
||||
print >> stream, '#ifndef BETTER_ENUMS_MACRO_FILE_H'
|
||||
print >> stream, '#define BETTER_ENUMS_MACRO_FILE_H'
|
||||
print >> stream, '#ifndef _BETTER_ENUM_MACRO_FILE_H_'
|
||||
print >> stream, '#define _BETTER_ENUM_MACRO_FILE_H_'
|
||||
|
||||
print >> stream, ''
|
||||
print >> stream, '#define BETTER_ENUMS_PP_MAP(macro, data, ...) \\'
|
||||
print >> stream, ' BETTER_ENUMS_ID( \\'
|
||||
print >> stream, ' BETTER_ENUMS_APPLY( \\'
|
||||
print >> stream, ' BETTER_ENUMS_PP_MAP_VAR_COUNT, \\'
|
||||
print >> stream, ' BETTER_ENUMS_PP_COUNT(__VA_ARGS__)) \\'
|
||||
print >> stream, '#define _ENUM_PP_MAP(macro, data, ...) \\'
|
||||
print >> stream, ' _ENUM_ID(_ENUM_A(_ENUM_PP_MAP_VAR_COUNT, ' + \
|
||||
'_ENUM_PP_COUNT(__VA_ARGS__)) \\'
|
||||
print >> stream, ' (macro, data, __VA_ARGS__))'
|
||||
|
||||
print >> stream, ''
|
||||
print >> stream, '#define BETTER_ENUMS_PP_MAP_VAR_COUNT(count) ' + \
|
||||
'BETTER_ENUMS_M ## count'
|
||||
print >> stream, '#define _ENUM_PP_MAP_VAR_COUNT(count) ' + \
|
||||
'_ENUM_M ## count'
|
||||
|
||||
print >> stream, ''
|
||||
print >> stream, '#define BETTER_ENUMS_APPLY(macro, ...) ' + \
|
||||
'BETTER_ENUMS_ID(macro(__VA_ARGS__))'
|
||||
print >> stream, '#define _ENUM_A(macro, ...) _ENUM_ID(macro(__VA_ARGS__))'
|
||||
|
||||
print >> stream, ''
|
||||
print >> stream, '#define BETTER_ENUMS_ID(x) x'
|
||||
print >> stream, '#define _ENUM_ID(x) x'
|
||||
|
||||
print >> stream, ''
|
||||
print >> stream, '#define BETTER_ENUMS_M1(m, d, x) m(d,0,x)'
|
||||
print >> stream, '#define _ENUM_M1(m, d, x) m(d,0,x)'
|
||||
for index in range(2, constants + 1):
|
||||
print >> stream, '#define BETTER_ENUMS_M' + str(index) + \
|
||||
'(m,d,x,...) m(d,' + str(index - 1) + ',x) \\'
|
||||
print >> stream, ' BETTER_ENUMS_ID(BETTER_ENUMS_M' + \
|
||||
str(index - 1) + '(m,d,__VA_ARGS__))'
|
||||
print >> stream, '#define _ENUM_M' + str(index) + \
|
||||
'(m,d,x,...) m(d,' + str(index - 1) + \
|
||||
',x) _ENUM_ID(_ENUM_M' + str(index - 1) + \
|
||||
'(m,d,__VA_ARGS__))'
|
||||
|
||||
print >> stream, ''
|
||||
pp_count_impl_prefix = '#define BETTER_ENUMS_PP_COUNT_IMPL(_1,'
|
||||
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))
|
||||
@ -110,11 +106,10 @@ def generate(stream, constants, length, script):
|
||||
print >> stream, ''
|
||||
|
||||
print >> stream, ''
|
||||
print >> stream, '#define BETTER_ENUMS_PP_COUNT(...) \\'
|
||||
pp_count_prefix = \
|
||||
' BETTER_ENUMS_ID(BETTER_ENUMS_PP_COUNT_IMPL(__VA_ARGS__,'
|
||||
'#define _ENUM_PP_COUNT(...) _ENUM_ID(_ENUM_PP_COUNT_IMPL(__VA_ARGS__,'
|
||||
stream.write(pp_count_prefix)
|
||||
pp_count = MultiLine(stream = stream, indent = 8,
|
||||
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) + ',')
|
||||
@ -122,7 +117,7 @@ def generate(stream, constants, length, script):
|
||||
print >> stream, ''
|
||||
|
||||
print >> stream, ''
|
||||
iterate_prefix = '#define BETTER_ENUMS_ITERATE(X, f, l)'
|
||||
iterate_prefix = '#define _ENUM_ITERATE(X, f, l)'
|
||||
stream.write(iterate_prefix)
|
||||
iterate = MultiLine(stream = stream, indent = 4,
|
||||
initial_column = len(iterate_prefix))
|
||||
@ -131,7 +126,7 @@ def generate(stream, constants, length, script):
|
||||
print >> stream, ''
|
||||
|
||||
print >> stream, ''
|
||||
print >> stream, '#endif // #ifndef BETTER_ENUMS_MACRO_FILE_H'
|
||||
print >> stream, '#endif // #ifndef _BETTER_ENUM_MACRO_FILE_H_'
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) != 3:
|
||||
|
||||
@ -1,203 +0,0 @@
|
||||
# Invoked automatically by the Makefile.
|
||||
|
||||
cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR)
|
||||
|
||||
project("Better Enums Testing" CXX)
|
||||
|
||||
|
||||
# Detect compiler feature support.
|
||||
|
||||
list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_constexpr CONSTEXPR_INDEX)
|
||||
if(CONSTEXPR_INDEX EQUAL -1)
|
||||
set(SUPPORTS_CONSTEXPR 0)
|
||||
else()
|
||||
set(SUPPORTS_CONSTEXPR 1)
|
||||
endif()
|
||||
|
||||
list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_relaxed_constexpr
|
||||
RELAXED_CONSTEXPR_INDEX)
|
||||
if(RELAXED_CONSTEXPR_INDEX EQUAL -1)
|
||||
set(SUPPORTS_RELAXED_CONSTEXPR 0)
|
||||
else()
|
||||
set(SUPPORTS_RELAXED_CONSTEXPR 1)
|
||||
endif()
|
||||
|
||||
# Current versions of CMake report VS2015 as supporting constexpr. However, the
|
||||
# support is too buggy to build Better Enums. Avoid trying to build constexpr
|
||||
# configurations on MSVC.
|
||||
if(${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC)
|
||||
set(SUPPORTS_CONSTEXPR 0)
|
||||
set(SUPPORTS_RELAXED_CONSTEXPR 0)
|
||||
endif()
|
||||
|
||||
list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_strong_enums ENUM_CLASS_INDEX)
|
||||
if(ENUM_CLASS_INDEX EQUAL -1)
|
||||
set(SUPPORTS_ENUM_CLASS 0)
|
||||
else()
|
||||
set(SUPPORTS_ENUM_CLASS 1)
|
||||
endif()
|
||||
|
||||
# Not supporting C++11 usage on g++46 due to buggy constexpr.
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7)
|
||||
set(SUPPORTS_CONSTEXPR 0)
|
||||
set(SUPPORTS_ENUM_CLASS 0)
|
||||
endif()
|
||||
|
||||
# Not supporting C++14 testing on clang++34 due to buggy library installed in
|
||||
# Travis Ubuntu image.
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL Clang
|
||||
AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.5)
|
||||
set(SUPPORTS_RELAXED_CONSTEXPR 0)
|
||||
endif()
|
||||
|
||||
|
||||
# Select standard based on the requested configuration. If the compiler does not
|
||||
# support the requested configuration, write a message and generate a no-op
|
||||
# build. This condition is not a failure.
|
||||
#
|
||||
# If no configuration is explicitly requested, default to compiling with no
|
||||
# special flags, with the latest standard supported by the compiler.
|
||||
|
||||
set(DO_NOT_TEST_FILE "${CMAKE_BINARY_DIR}/do-not-test")
|
||||
|
||||
if(CONFIGURATION STREQUAL CONSTEXPR)
|
||||
if(SUPPORTS_CONSTEXPR)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
else()
|
||||
message(WARNING "This compiler does not support constexpr")
|
||||
file(WRITE "${DO_NOT_TEST_FILE}")
|
||||
return()
|
||||
endif()
|
||||
elseif(CONFIGURATION STREQUAL FULL_CONSTEXPR)
|
||||
if(SUPPORTS_CONSTEXPR)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
add_definitions(-DBETTER_ENUMS_CONSTEXPR_TO_STRING)
|
||||
else()
|
||||
message(WARNING "This compiler does not support constexpr")
|
||||
file(WRITE "${DO_NOT_TEST_FILE}")
|
||||
return()
|
||||
endif()
|
||||
elseif(CONFIGURATION STREQUAL STRICT_CONVERSION)
|
||||
if(SUPPORTS_ENUM_CLASS)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
add_definitions(-DBETTER_ENUMS_STRICT_CONVERSION)
|
||||
else()
|
||||
message(WARNING "This compiler does not support enum class")
|
||||
file(WRITE "${DO_NOT_TEST_FILE}")
|
||||
return()
|
||||
endif()
|
||||
elseif(CONFIGURATION STREQUAL CXX98)
|
||||
set(CMAKE_CXX_STANDARD 98)
|
||||
elseif(CONFIGURATION STREQUAL CXX14)
|
||||
if(SUPPORTS_RELAXED_CONSTEXPR)
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
else()
|
||||
message(WARNING "This compiler does not support relaxed constexpr")
|
||||
file(WRITE "${DO_NOT_TEST_FILE}")
|
||||
return()
|
||||
endif()
|
||||
else()
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
endif()
|
||||
|
||||
|
||||
# Basic tests.
|
||||
|
||||
add_executable(cxxtest cxxtest/tests.cc)
|
||||
add_executable(linking linking/helper.cc linking/main.cc)
|
||||
|
||||
set(PERFORMANCE_TESTS
|
||||
1-simple 2-include_empty 3-only_include_enum 4-declare_enums 5-iostream)
|
||||
|
||||
foreach(TEST ${PERFORMANCE_TESTS})
|
||||
add_executable(performance-${TEST} performance/${TEST}.cc)
|
||||
endforeach(TEST)
|
||||
|
||||
|
||||
# Select examples to build.
|
||||
|
||||
set(EXAMPLES
|
||||
1-hello-world 2-conversions 3-iterate 4-switch 6-iostreams 7-safety
|
||||
8-representation 9-constexpr 101-special-values 103-bitset 104-quine
|
||||
105-c++17-reflection)
|
||||
|
||||
set(SKIPPED_FOR_CXX98
|
||||
5-map 9-constexpr 101-special-values 103-bitset 104-quine
|
||||
105-c++17-reflection)
|
||||
|
||||
set(SKIPPED_FOR_STRICT_CONVERSION 4-switch)
|
||||
|
||||
if(CONFIGURATION STREQUAL CXX98 OR NOT SUPPORTS_CONSTEXPR)
|
||||
list(REMOVE_ITEM EXAMPLES ${SKIPPED_FOR_CXX98})
|
||||
endif()
|
||||
|
||||
if(CONFIGURATION STREQUAL STRICT_CONVERSION)
|
||||
list(REMOVE_ITEM EXAMPLES ${SKIPPED_FOR_STRICT_CONVERSION})
|
||||
endif()
|
||||
|
||||
if(CONFIGURATION STREQUAL CXX14)
|
||||
set(EXAMPLES 5-map)
|
||||
endif()
|
||||
|
||||
foreach(EXAMPLE ${EXAMPLES})
|
||||
add_executable(example-${EXAMPLE} ../example/${EXAMPLE}.cc)
|
||||
endforeach(EXAMPLE)
|
||||
|
||||
|
||||
# Add compiler flags.
|
||||
|
||||
include_directories(..)
|
||||
include_directories(../extra)
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES Clang)
|
||||
include(CheckCXXCompilerFlag)
|
||||
|
||||
macro(add_cxx_flag_if_supported FLAG)
|
||||
check_cxx_compiler_flag("${FLAG}" HAVE_FLAG_${FLAG})
|
||||
|
||||
if(HAVE_FLAG_${FLAG})
|
||||
add_definitions(${FLAG})
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(add_cxx_flag_to_target_if_supported TARGET FLAG)
|
||||
string(REPLACE "=" "_equals_" ESCAPED ${FLAG})
|
||||
string(REPLACE "+" "_plus_" ESCAPED ${ESCAPED})
|
||||
check_cxx_compiler_flag("${FLAG}" HAVE_FLAG_${FLAG})
|
||||
|
||||
if(HAVE_FLAG_${FLAG})
|
||||
get_target_property(FLAGS ${TARGET} COMPILE_FLAGS)
|
||||
if(${FLAGS} STREQUAL "FLAGS-NOTFOUND")
|
||||
set(FLAGS "")
|
||||
endif()
|
||||
set_target_properties(
|
||||
${TARGET} PROPERTIES COMPILE_FLAGS "${FLAGS} ${FLAG}")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
add_cxx_flag_if_supported("-Wpedantic")
|
||||
add_cxx_flag_if_supported("-Wall")
|
||||
add_cxx_flag_if_supported("-Wextra")
|
||||
add_cxx_flag_if_supported("-Wno-variadic-macros")
|
||||
add_cxx_flag_if_supported("-Wno-unused-const-variable")
|
||||
|
||||
add_cxx_flag_to_target_if_supported(linking "-Weverything")
|
||||
add_cxx_flag_to_target_if_supported(linking "-Wno-c++98-compat-pedantic")
|
||||
add_cxx_flag_to_target_if_supported(linking "-Wno-padded")
|
||||
add_cxx_flag_to_target_if_supported(linking "-Wno-global-constructors")
|
||||
add_cxx_flag_to_target_if_supported(linking "-Wno-old-style-cast")
|
||||
add_cxx_flag_to_target_if_supported(linking "-Wno-missing-prototypes")
|
||||
add_cxx_flag_to_target_if_supported(linking "-Wshadow")
|
||||
add_cxx_flag_to_target_if_supported(linking "-Weffc++")
|
||||
add_cxx_flag_to_target_if_supported(linking "-Wstrict-aliasing")
|
||||
add_cxx_flag_to_target_if_supported(linking "-Wformat")
|
||||
add_cxx_flag_to_target_if_supported(linking "-Wmissing-include-dirs")
|
||||
add_cxx_flag_to_target_if_supported(linking "-Wsync-nand")
|
||||
add_cxx_flag_to_target_if_supported(linking "-Wconditionally-supported")
|
||||
add_cxx_flag_to_target_if_supported(linking "-Wconversion")
|
||||
add_cxx_flag_to_target_if_supported(linking "-Wuseless-cast")
|
||||
|
||||
add_definitions("-Werror")
|
||||
endif()
|
||||
168
test/Makefile
168
test/Makefile
@ -1,167 +1,13 @@
|
||||
# Run "make" for quick builds while developing.
|
||||
# Run "make default-all" before submitting a pull request.
|
||||
# Run "make clean" to clean up.
|
||||
# See doc/CONTRIBUTING.md for full instructions.
|
||||
|
||||
CXXTEST_GENERATED := cxxtest/tests.cc
|
||||
|
||||
UNIX_MAKE_COMMAND := make
|
||||
WINDOWS_MAKE_COMMAND := "MSBuild.exe \"Better Enums Testing.sln\""
|
||||
|
||||
UNIX_OUTPUT_DIRECTORY := .
|
||||
WINDOWS_OUTPUT_DIRECTORY := Debug
|
||||
|
||||
ifdef COMSPEC
|
||||
WIN32 := true
|
||||
endif
|
||||
ifdef ComSpec
|
||||
WIN32 := true
|
||||
endif
|
||||
|
||||
ifndef WIN32
|
||||
|
||||
DEFAULT_MAKE_COMMAND := $(UNIX_MAKE_COMMAND)
|
||||
DEFAULT_OUTPUT_DIRECTORY := $(UNIX_OUTPUT_DIRECTORY)
|
||||
define PATH_FIX
|
||||
@true
|
||||
endef
|
||||
SUFFIX :=
|
||||
CXXTESTGEN := cxxtestgen
|
||||
|
||||
else
|
||||
|
||||
DEFAULT_MAKE_COMMAND := $(WINDOWS_MAKE_COMMAND)
|
||||
DEFAULT_OUTPUT_DIRECTORY := $(WINDOWS_OUTPUT_DIRECTORY)
|
||||
define PATH_FIX
|
||||
sed 's!include "/!include "C:/cygwin/!g' $1 > $$$$ && mv $$$$ $1
|
||||
endef
|
||||
SUFFIX := .exe
|
||||
CXXTESTGEN := python `which cxxtestgen | sed -E 's!(/cygdrive)?/c/!c:/!'`
|
||||
|
||||
endif
|
||||
|
||||
DEFAULTS := \
|
||||
TITLE=default \
|
||||
MAKE_COMMAND=$(DEFAULT_MAKE_COMMAND) \
|
||||
OUTPUT_DIRECTORY=$(DEFAULT_OUTPUT_DIRECTORY)
|
||||
|
||||
# Builds one configuration with the system compiler. This will be either a
|
||||
# regular C++11 or C++98 build (no constexpr to_string and no strict
|
||||
# conversions).
|
||||
.PHONY : default
|
||||
default : examples
|
||||
make $(DEFAULTS) one-configuration
|
||||
|
||||
# Builds all configurations with the system compiler.
|
||||
.PHONY : default-all
|
||||
default-all : examples
|
||||
make $(DEFAULTS) all-configurations
|
||||
|
||||
.PHONY : examples
|
||||
examples :
|
||||
default :
|
||||
make -C ../doc examples
|
||||
python test.py
|
||||
|
||||
# Example: make COMPILER=clang++36 unix
|
||||
.PHONY : unix
|
||||
unix :
|
||||
make TITLE=$(COMPILER) CMAKE_OPTIONS="-DCMAKE_CXX_COMPILER=$(COMPILER)" \
|
||||
MAKE_COMMAND=$(UNIX_MAKE_COMMAND) \
|
||||
OUTPUT_DIRECTORY=$(UNIX_OUTPUT_DIRECTORY) all-configurations
|
||||
|
||||
# Example: make TITLE=vc2013 COMPILER="Visual Studio 12 2013" ms
|
||||
.PHONY : ms
|
||||
ms :
|
||||
make TITLE=$(TITLE) CMAKE_OPTIONS="-G \\\"$(COMPILER)\\\"" \
|
||||
MAKE_COMMAND=$(WINDOWS_MAKE_COMMAND) \
|
||||
OUTPUT_DIRECTORY=$(WINDOWS_OUTPUT_DIRECTORY) all-configurations
|
||||
|
||||
# Expects three variables to be defined:
|
||||
# CMAKE_OPTIONS:
|
||||
# First, the compiler:
|
||||
# - Empty for a "default" build.
|
||||
# - -G "Visual Studio XX YYYY" to select a specific Microsoft compiler.
|
||||
# - -DCMAKE_CXX_COMPILER=AAA to select a specific Unix compiler binary.
|
||||
# Configuration selection (e.g. -DCONFIGURATION=CXX98) also go here.
|
||||
# TITLE:
|
||||
# The build title (subdirectory). Some combination of compiler/configuration.
|
||||
# MAKE_COMMAND:
|
||||
# Either make or msbuild "Better Enums Testing.sln"
|
||||
# OUTPUT_DIRECTORY:
|
||||
# Path to generated binaries relative to build directory. Either "." or
|
||||
# "Debug".
|
||||
.PHONY : one-configuration
|
||||
one-configuration : $(CXXTEST_GENERATED)
|
||||
mkdir -p build/$(TITLE)
|
||||
cd build/$(TITLE) && cmake $(CMAKE_OPTIONS) ../.. && $(MAKE_COMMAND)
|
||||
rm -rf build/$(TITLE)/bin
|
||||
[ -f build/$(TITLE)/do-not-test ] || \
|
||||
( ln -s $(OUTPUT_DIRECTORY) build/$(TITLE)/bin && \
|
||||
make BIN=build/$(TITLE)/bin run-tests )
|
||||
|
||||
.PHONY : run-tests
|
||||
run-tests :
|
||||
$(BIN)/cxxtest
|
||||
@for FILE in $(BIN)/example-*$(SUFFIX) ; \
|
||||
do \
|
||||
EXAMPLE=$$(basename $$FILE | sed s/\.exe$$// | sed s/^example-//) ; \
|
||||
$$FILE | sed 's/\r$$//' | cmp - expect/$$EXAMPLE ; \
|
||||
RESULT=$$? ; \
|
||||
if [ $$RESULT -ne 0 ] ; \
|
||||
then \
|
||||
echo \'$$FILE\' produced bad output ; \
|
||||
exit $$RESULT ; \
|
||||
fi ; \
|
||||
done
|
||||
@echo Example program output matches expected output
|
||||
|
||||
.PHONY : all-configurations
|
||||
all-configurations :
|
||||
make TITLE=$(TITLE)-c++11 \
|
||||
CMAKE_OPTIONS="$(CMAKE_OPTIONS) -DCONFIGURATION=CONSTEXPR" \
|
||||
one-configuration
|
||||
make TITLE=$(TITLE)-full-constexpr \
|
||||
CMAKE_OPTIONS="$(CMAKE_OPTIONS) -DCONFIGURATION=FULL_CONSTEXPR" \
|
||||
one-configuration
|
||||
make TITLE=$(TITLE)-enum-class \
|
||||
CMAKE_OPTIONS="$(CMAKE_OPTIONS) -DCONFIGURATION=STRICT_CONVERSION" \
|
||||
one-configuration
|
||||
make TITLE=$(TITLE)-c++14 \
|
||||
CMAKE_OPTIONS="$(CMAKE_OPTIONS) -DCONFIGURATION=CXX14" \
|
||||
one-configuration
|
||||
make TITLE=$(TITLE)-c++98 \
|
||||
CMAKE_OPTIONS="$(CMAKE_OPTIONS) -DCONFIGURATION=CXX98" \
|
||||
one-configuration
|
||||
|
||||
.PHONY : all-unix
|
||||
all-unix : examples
|
||||
make COMPILER=clang++39 unix
|
||||
make COMPILER=clang++38 unix
|
||||
make COMPILER=clang++37 unix
|
||||
make COMPILER=g++52 unix
|
||||
make COMPILER=g++46 unix
|
||||
make COMPILER=g++47 unix
|
||||
make COMPILER=g++43 unix
|
||||
make COMPILER=g++48 unix
|
||||
make COMPILER=g++49 unix
|
||||
make COMPILER=g++44 unix
|
||||
make COMPILER=g++45 unix
|
||||
make COMPILER=clang++33 unix
|
||||
make COMPILER=clang++34 unix
|
||||
make COMPILER=clang++35 unix
|
||||
make COMPILER=clang++36 unix
|
||||
|
||||
.PHONY : all-ms
|
||||
all-ms : examples
|
||||
make TITLE=vc2015 COMPILER="Visual Studio 14 2015" ms
|
||||
make TITLE=vc2008 COMPILER="Visual Studio 9 2008" ms
|
||||
make TITLE=vc2010 COMPILER="Visual Studio 10 2010" ms
|
||||
make TITLE=vc2012 COMPILER="Visual Studio 11 2012" ms
|
||||
make TITLE=vc2013 COMPILER="Visual Studio 12 2013" ms
|
||||
|
||||
$(CXXTEST_GENERATED) : cxxtest/*.h
|
||||
$(CXXTESTGEN) --error-printer -o $@ $^
|
||||
$(call PATH_FIX,$@)
|
||||
.PHONY : platform
|
||||
platform :
|
||||
make -C ../doc examples
|
||||
python test.py --all
|
||||
|
||||
.PHONY : clean
|
||||
clean :
|
||||
rm -rf build $(CXXTEST_GENERATED)
|
||||
rm -rf platform *.obj
|
||||
|
||||
@ -1,29 +0,0 @@
|
||||
#include <cxxtest/TestSuite.h>
|
||||
#include <iostream>
|
||||
#include <enum.h>
|
||||
|
||||
|
||||
|
||||
BETTER_ENUM(Compiler, int, GCC, Clang, MSVC)
|
||||
|
||||
|
||||
|
||||
class StreamOperatorTests : public CxxTest::TestSuite {
|
||||
public:
|
||||
void test_output()
|
||||
{
|
||||
std::stringstream stream;
|
||||
|
||||
stream << +Compiler::GCC;
|
||||
TS_ASSERT_EQUALS(strcmp(stream.str().c_str(), "GCC"), 0);
|
||||
}
|
||||
|
||||
void test_input()
|
||||
{
|
||||
std::stringstream stream("Clang");
|
||||
Compiler compiler = Compiler::GCC;
|
||||
|
||||
stream >> compiler;
|
||||
TS_ASSERT_EQUALS(compiler, +Compiler::Clang);
|
||||
}
|
||||
};
|
||||
@ -1,4 +1,3 @@
|
||||
#include <iosfwd>
|
||||
#include <stdexcept>
|
||||
#include <cxxtest/TestSuite.h>
|
||||
#include <enum.h>
|
||||
@ -13,28 +12,17 @@
|
||||
|
||||
|
||||
|
||||
BETTER_ENUM(Channel, short, Red, Green, Blue)
|
||||
BETTER_ENUM(Depth, short, HighColor = 40, TrueColor = 20)
|
||||
BETTER_ENUM(Compression, short, None, Huffman, Default = Huffman)
|
||||
ENUM(Channel, short, Red, Green, Blue)
|
||||
ENUM(Depth, short, HighColor = 40, TrueColor = 20)
|
||||
ENUM(Compression, short, None, Huffman, Default = Huffman)
|
||||
|
||||
|
||||
|
||||
namespace test {
|
||||
|
||||
BETTER_ENUM(Namespaced, short, One, Two)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Using BETTER_ENUMS_HAVE_CONSTEXPR_ as a proxy for C++11 support. This should
|
||||
// be changed to be more precise in the future.
|
||||
#ifdef BETTER_ENUMS_HAVE_CONSTEXPR_
|
||||
|
||||
BETTER_ENUMS_DECLARE_STD_HASH(Channel)
|
||||
// Using _ENUM_HAVE_CONSTEXPR as a proxy for C++11 support. This should be
|
||||
// changed to be more precise in the future.
|
||||
#ifdef _ENUM_HAVE_CONSTEXPR
|
||||
|
||||
#include <type_traits>
|
||||
#include <functional>
|
||||
|
||||
// Type properties.
|
||||
static_assert_1(std::is_class<Channel>());
|
||||
@ -48,14 +36,12 @@ static_assert_1(std::is_integral<Channel::_integral>());
|
||||
static_assert_1(std::is_enum<Channel::_enumerated>());
|
||||
|
||||
static_assert_1((std::is_same<short, Channel::_integral>()));
|
||||
// Temporarily disabled due to outdated libraries in Travis.
|
||||
// static_assert_1((std::is_same<
|
||||
// short, std::underlying_type<Channel::_enumerated>::type>()));
|
||||
static_assert_1((std::is_same<
|
||||
short, std::underlying_type<Channel::_enumerated>::type>()));
|
||||
|
||||
static_assert_1(!(std::is_same<int, Channel::_integral>()));
|
||||
// Temporarily disabled due to outdated libraries in Travis.
|
||||
// static_assert_1(!(std::is_same<
|
||||
// int, std::underlying_type<Channel::_enumerated>::type>()));
|
||||
static_assert_1(!(std::is_same<
|
||||
int, std::underlying_type<Channel::_enumerated>::type>()));
|
||||
|
||||
static_assert_1(sizeof(Channel) == sizeof(short));
|
||||
static_assert_1(alignof(Channel) == alignof(short));
|
||||
@ -66,16 +52,13 @@ static_assert_1((std::is_same<decltype(Channel::Red), Channel::_enumerated>()));
|
||||
|
||||
// Supported constructors.
|
||||
|
||||
// Apparently, this isn't supported by Clang in Travis.
|
||||
// #ifdef __clang__
|
||||
// static_assert_1(std::is_trivially_copyable<Channel>());
|
||||
// #endif
|
||||
#ifdef __clang__
|
||||
static_assert_1(std::is_trivially_copyable<Channel>());
|
||||
#endif
|
||||
|
||||
static_assert_1((std::is_constructible<Channel, Channel::_enumerated>()));
|
||||
// "Passes" by causing a compilation error.
|
||||
// static_assert_1(!(std::is_constructible<Channel, Channel::_integral>()));
|
||||
// "Passes" on most compilers, passes on g++47 by causing a compilation error.
|
||||
// static_assert_1(!(std::is_constructible<Channel, Depth>()));
|
||||
static_assert_1(!(std::is_constructible<Channel, Channel::_integral>()));
|
||||
static_assert_1(!(std::is_constructible<Channel, Depth>()));
|
||||
|
||||
// Commented out temporarily due to GCC 4.7- bug.
|
||||
// static_assert_1(!std::is_default_constructible<Channel>());
|
||||
@ -123,23 +106,12 @@ static_assert_1(
|
||||
static_assert_1(Channel::_is_valid("Green"));
|
||||
static_assert_1(Channel::_is_valid_nocase("green"));
|
||||
|
||||
static_assert_1(Channel::_size() == 3);
|
||||
static_assert_1(Channel::_size == 3);
|
||||
static_assert_1(Channel::_values().size() == 3);
|
||||
static_assert_1(*Channel::_values().begin() == +Channel::Red);
|
||||
static_assert_1(*(Channel::_values().end() - 1) == +Channel::Blue);
|
||||
static_assert_1(Channel::_values()[1] == +Channel::Green);
|
||||
|
||||
namespace name_clash_test {
|
||||
|
||||
struct Foo {};
|
||||
std::ostream& operator<<(std::ostream&, Foo);
|
||||
|
||||
BETTER_ENUM(Enum, int, ONE, TWO, THREE)
|
||||
|
||||
static_assert_1((std::is_same<decltype(std::declval<std::ostream&>() << +Enum::ONE), std::ostream&>()));
|
||||
|
||||
}
|
||||
|
||||
#ifdef BETTER_ENUMS_CONSTEXPR_TO_STRING
|
||||
|
||||
constexpr bool same_string(const char *r, const char *s, size_t index = 0)
|
||||
@ -164,24 +136,6 @@ static_assert_1(same_string(Depth::_names()[0], "HighColor"));
|
||||
|
||||
|
||||
// Run-time testing.
|
||||
class HashTests : public CxxTest::TestSuite {
|
||||
public:
|
||||
void test_same_values()
|
||||
{
|
||||
#ifdef _ENUM_HAVE_CONSTEXPR
|
||||
TS_ASSERT_EQUALS(
|
||||
std::hash<Channel>().operator()(Channel::Red),
|
||||
std::hash<int>().operator()(0));
|
||||
TS_ASSERT_EQUALS(
|
||||
std::hash<Channel>().operator()(Channel::Green),
|
||||
std::hash<int>().operator()(1));
|
||||
TS_ASSERT_EQUALS(
|
||||
std::hash<Channel>().operator()(Channel::Blue),
|
||||
std::hash<int>().operator()(2));
|
||||
#endif // #ifdef _ENUM_HAVE_CONSTEXPR
|
||||
}
|
||||
};
|
||||
|
||||
class EnumTests : public CxxTest::TestSuite {
|
||||
public:
|
||||
void test_constant_values()
|
||||
@ -256,9 +210,9 @@ class EnumTests : public CxxTest::TestSuite {
|
||||
|
||||
void test_value_iterable()
|
||||
{
|
||||
TS_ASSERT_EQUALS(Channel::_size(), 3);
|
||||
TS_ASSERT_EQUALS(Depth::_size(), 2);
|
||||
TS_ASSERT_EQUALS(Channel::_values().size(), Channel::_size());
|
||||
TS_ASSERT_EQUALS(Channel::_size, 3);
|
||||
TS_ASSERT_EQUALS(Depth::_size, 2);
|
||||
TS_ASSERT_EQUALS(Channel::_values().size(), Channel::_size);
|
||||
TS_ASSERT_EQUALS(*Channel::_values().begin(), +Channel::Red);
|
||||
TS_ASSERT_EQUALS(*(Channel::_values().begin() + 1), +Channel::Green);
|
||||
TS_ASSERT_EQUALS(*(Channel::_values().begin() + 2), +Channel::Blue);
|
||||
@ -283,7 +237,7 @@ class EnumTests : public CxxTest::TestSuite {
|
||||
|
||||
void test_name_iterable()
|
||||
{
|
||||
TS_ASSERT_EQUALS(Channel::_names().size(), Channel::_size());
|
||||
TS_ASSERT_EQUALS(Channel::_names().size(), Channel::_size);
|
||||
TS_ASSERT_EQUALS(strcmp(*Channel::_names().begin(), "Red"), 0);
|
||||
TS_ASSERT_EQUALS(strcmp(Channel::_names()[0], "Red"), 0);
|
||||
TS_ASSERT_EQUALS(strcmp(Depth::_names()[0], "HighColor"), 0);
|
||||
@ -315,120 +269,4 @@ class EnumTests : public CxxTest::TestSuite {
|
||||
{
|
||||
TS_ASSERT_EQUALS(Compression::Default, Compression::Huffman);
|
||||
}
|
||||
|
||||
void test_namespaced()
|
||||
{
|
||||
TS_ASSERT_EQUALS((+test::Namespaced::One)._to_integral(), 0);
|
||||
TS_ASSERT_EQUALS(test::Namespaced::_from_integral(0),
|
||||
+test::Namespaced::One);
|
||||
TS_ASSERT_EQUALS(strcmp((+test::Namespaced::One)._to_string(), "One"),
|
||||
0);
|
||||
TS_ASSERT_EQUALS(test::Namespaced::_from_string("Two"),
|
||||
+test::Namespaced::Two);
|
||||
|
||||
TS_ASSERT_EQUALS(test::Namespaced::_values()[0],
|
||||
+test::Namespaced::One);
|
||||
TS_ASSERT_EQUALS(strcmp(test::Namespaced::_names()[0], "One"), 0);
|
||||
|
||||
TS_ASSERT_EQUALS(*test::Namespaced::_values().begin(),
|
||||
+test::Namespaced::One);
|
||||
TS_ASSERT_EQUALS(strcmp(*test::Namespaced::_names().begin(), "One"), 0);
|
||||
}
|
||||
|
||||
void test_to_index()
|
||||
{
|
||||
TS_ASSERT_EQUALS((+Channel::Red)._to_index(), 0);
|
||||
TS_ASSERT_EQUALS((+Channel::Green)._to_index(), 1);
|
||||
TS_ASSERT_EQUALS((+Channel::Blue)._to_index(), 2);
|
||||
|
||||
TS_ASSERT_EQUALS((+Depth::HighColor)._to_index(), 0);
|
||||
TS_ASSERT_EQUALS((+Depth::TrueColor)._to_index(), 1);
|
||||
|
||||
TS_ASSERT_EQUALS((+Compression::None)._to_index(), 0);
|
||||
TS_ASSERT_EQUALS((+Compression::Huffman)._to_index(), 1);
|
||||
// TS_ASSERT_EQUALS((+Compression::Default)._to_index(), 2); // This won't pass as Compression::Huffman == Compression::Default
|
||||
}
|
||||
|
||||
void test_from_index()
|
||||
{
|
||||
TS_ASSERT_EQUALS((+Channel::Red), Channel::_from_index(0));
|
||||
TS_ASSERT_EQUALS((+Channel::Green), Channel::_from_index(1));
|
||||
TS_ASSERT_EQUALS((+Channel::Blue), Channel::_from_index(2));
|
||||
TS_ASSERT_THROWS(Channel::_from_index(42), std::runtime_error);
|
||||
|
||||
TS_ASSERT_EQUALS((+Depth::HighColor), Depth::_from_index(0));
|
||||
TS_ASSERT_EQUALS((+Depth::TrueColor), Depth::_from_index(1));
|
||||
TS_ASSERT_THROWS(Depth::_from_index(42), std::runtime_error);
|
||||
|
||||
TS_ASSERT_EQUALS((+Compression::None), Compression::_from_index(0));
|
||||
TS_ASSERT_EQUALS((+Compression::Huffman), Compression::_from_index(1));
|
||||
TS_ASSERT_EQUALS((+Compression::Default), Compression::_from_index(2));
|
||||
TS_ASSERT_THROWS(Compression::_from_index(42), std::runtime_error);
|
||||
}
|
||||
|
||||
void test_from_index_nothrow()
|
||||
{
|
||||
better_enums::optional<Channel> maybe_channel = Channel::_from_index_nothrow(0);
|
||||
TS_ASSERT(maybe_channel);
|
||||
TS_ASSERT_EQUALS(*maybe_channel, +Channel::Red);
|
||||
|
||||
maybe_channel = Channel::_from_index_nothrow(1);
|
||||
TS_ASSERT(maybe_channel);
|
||||
TS_ASSERT_EQUALS(*maybe_channel, +Channel::Green);
|
||||
|
||||
maybe_channel = Channel::_from_index_nothrow(2);
|
||||
TS_ASSERT(maybe_channel);
|
||||
TS_ASSERT_EQUALS(*maybe_channel, +Channel::Blue);
|
||||
|
||||
maybe_channel = Channel::_from_index_nothrow(45);
|
||||
TS_ASSERT(!maybe_channel);
|
||||
|
||||
better_enums::optional<Depth> maybe_depth = Depth::_from_index_nothrow(0);
|
||||
TS_ASSERT(maybe_depth);
|
||||
TS_ASSERT_EQUALS(*maybe_depth, +Depth::HighColor);
|
||||
|
||||
maybe_depth = Depth::_from_index_nothrow(1);
|
||||
TS_ASSERT(maybe_depth);
|
||||
TS_ASSERT_EQUALS(*maybe_depth, +Depth::TrueColor);
|
||||
|
||||
maybe_depth = Depth::_from_index_nothrow(45);
|
||||
TS_ASSERT(!maybe_depth);
|
||||
|
||||
better_enums::optional<Compression> maybe_compression = Compression::_from_index_nothrow(0);
|
||||
TS_ASSERT(maybe_compression);
|
||||
TS_ASSERT_EQUALS(*maybe_compression, +Compression::None);
|
||||
|
||||
maybe_compression = Compression::_from_index_nothrow(1);
|
||||
TS_ASSERT(maybe_compression);
|
||||
TS_ASSERT_EQUALS(*maybe_compression, +Compression::Huffman);
|
||||
|
||||
maybe_compression = Compression::_from_index_nothrow(2);
|
||||
TS_ASSERT(maybe_compression);
|
||||
TS_ASSERT_EQUALS(*maybe_compression, +Compression::Default);
|
||||
|
||||
maybe_compression = Compression::_from_index_nothrow(45);
|
||||
TS_ASSERT(!maybe_compression);
|
||||
}
|
||||
|
||||
void test_from_index_unchecked()
|
||||
{
|
||||
|
||||
TS_ASSERT_EQUALS((+Channel::Red), Channel::_from_index_unchecked(0));
|
||||
TS_ASSERT_EQUALS((+Channel::Green), Channel::_from_index_unchecked(1));
|
||||
TS_ASSERT_EQUALS((+Channel::Blue), Channel::_from_index_unchecked(2));
|
||||
|
||||
TS_ASSERT_EQUALS((+Depth::HighColor), Depth::_from_index_unchecked(0));
|
||||
TS_ASSERT_EQUALS((+Depth::TrueColor), Depth::_from_index_unchecked(1));
|
||||
|
||||
TS_ASSERT_EQUALS((+Compression::None), Compression::_from_index_unchecked(0));
|
||||
TS_ASSERT_EQUALS((+Compression::Huffman), Compression::_from_index_unchecked(1));
|
||||
TS_ASSERT_EQUALS((+Compression::Default), Compression::_from_index_unchecked(2));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
BETTER_ENUM(InternalNameCollisions, int,
|
||||
EnumClassForSwitchStatements, PutNamesInThisScopeAlso,
|
||||
force_initialization, value_array, raw_names, name_storage,
|
||||
name_array, initialized, the_raw_names, the_name_array)
|
||||
@ -1,4 +0,0 @@
|
||||
Red component: c4
|
||||
Green component: 74
|
||||
Blue component: 51
|
||||
darksalmon
|
||||
2
test/expect/103-quine
Normal file
2
test/expect/103-quine
Normal file
@ -0,0 +1,2 @@
|
||||
ENUM(Channel, int, Red = 0, Green = 1, Blue = 2)
|
||||
ENUM(Depth, int, TrueColor = 1, HighColor = 0)
|
||||
@ -1,2 +0,0 @@
|
||||
BETTER_ENUM(Channel, int, Red = 0, Green = 1, Blue = 2)
|
||||
BETTER_ENUM(Depth, int, TrueColor = 1, HighColor = 0)
|
||||
@ -1 +0,0 @@
|
||||
Blue
|
||||
@ -1,4 +0,0 @@
|
||||
the red channel
|
||||
the red channel
|
||||
Green
|
||||
Blue
|
||||
@ -1 +0,0 @@
|
||||
Red
|
||||
@ -4,5 +4,4 @@
|
||||
void print(Channel channel)
|
||||
{
|
||||
std::cout << Channel::_name() << "::" << channel._to_string() << std::endl;
|
||||
std::cout << Channel::_size() << std::endl;
|
||||
}
|
||||
8
test/link/helper.h
Normal file
8
test/link/helper.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef _HELPER_H_
|
||||
#define _HELPER_H_
|
||||
|
||||
#include "shared.h"
|
||||
|
||||
void print(Channel channel);
|
||||
|
||||
#endif // #ifndef _HELPER_H_
|
||||
8
test/link/shared.h
Normal file
8
test/link/shared.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef _SHARED_H_
|
||||
#define _SHARED_H_
|
||||
|
||||
#include <enum.h>
|
||||
|
||||
ENUM(Channel, int, Red, Green, Blue)
|
||||
|
||||
#endif // #ifndef _SHARED_H_
|
||||
@ -1,8 +0,0 @@
|
||||
#ifndef HELPER_H
|
||||
#define HELPER_H
|
||||
|
||||
#include "shared.h"
|
||||
|
||||
void print(Channel channel);
|
||||
|
||||
#endif // #ifndef HELPER_H
|
||||
@ -1,8 +0,0 @@
|
||||
#ifndef SHARED_H
|
||||
#define SHARED_H
|
||||
|
||||
#include <enum.h>
|
||||
|
||||
BETTER_ENUM(Channel, int, Red, Green, Blue)
|
||||
|
||||
#endif // #ifndef SHARED_H
|
||||
@ -1,223 +1,219 @@
|
||||
#include <enum.h>
|
||||
|
||||
BETTER_ENUM(Channel, int,
|
||||
Red, Green, Blue, Cyan, Magenta, Yellow, Black, Hue, Saturation,
|
||||
Value)
|
||||
ENUM(Channel, int,
|
||||
Red, Green, Blue, Cyan, Magenta, Yellow, Black, Hue, Saturation, Value)
|
||||
|
||||
BETTER_ENUM(Direction, int,
|
||||
North, East, South, West, NorthEast, SouthEast, SouthWest,
|
||||
NorthWest, NorthNorthEast, EastNorthEast, EastSouthEast,
|
||||
SouthSouthEast, SouthSouthWest, WestSouthWest, WestNorthWest,
|
||||
NorthNorthWest)
|
||||
ENUM(Direction, int,
|
||||
North, East, South, West, NorthEast, SouthEast, SouthWest, NorthWest,
|
||||
NorthNorthEast, EastNorthEast, EastSouthEast, SouthSouthEast,
|
||||
SouthSouthWest, WestSouthWest, WestNorthWest, NorthNorthWest)
|
||||
|
||||
BETTER_ENUM(ASTNode, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||
ENUM(ASTNode, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
||||
BasicType, ArrowType, VariantTypeConstant)
|
||||
|
||||
BETTER_ENUM(State, int,
|
||||
Attacking, Defending, Searching, Pursuing, Hungry, Fleeing,
|
||||
Confused, Healing, Stunned)
|
||||
ENUM(State, int,
|
||||
Attacking, Defending, Searching, Pursuing, Hungry, Fleeing, Confused,
|
||||
Healing, Stunned)
|
||||
|
||||
BETTER_ENUM(APIMethod, int,
|
||||
ReadPost, WritePost, PollPost, ReadImage, WriteImage, PollImage,
|
||||
ReadKey, WriteKey, PollKey, ReadUser, WriteUser, PollUser,
|
||||
ReadOrganization, WriteOrganization, PollOrganization, ReadGroup,
|
||||
WriteGroup, PollGroup, ReadProject, WriteProject, PollProject,
|
||||
ReadComment, WriteComment, PollComment, ReadPermission,
|
||||
WritePermission, PollPermission, ReadOwner, WriteOwner, PollOwner,
|
||||
ReadProposal, WriteProposal, PollProposal, ReadHistory,
|
||||
WriteHistory, PollHistory)
|
||||
ENUM(APIMethod, int,
|
||||
ReadPost, WritePost, PollPost, ReadImage, WriteImage, PollImage, ReadKey,
|
||||
WriteKey, PollKey, ReadUser, WriteUser, PollUser, ReadOrganization,
|
||||
WriteOrganization, PollOrganization, ReadGroup, WriteGroup, PollGroup,
|
||||
ReadProject, WriteProject, PollProject, ReadComment, WriteComment,
|
||||
PollComment, ReadPermission, WritePermission, PollPermission, ReadOwner,
|
||||
WriteOwner, PollOwner, ReadProposal, WriteProposal, PollProposal,
|
||||
ReadHistory, WriteHistory, PollHistory)
|
||||
|
||||
BETTER_ENUM(Lipsum, int,
|
||||
Lorem, ipsum, dolor, sit, amet, consectetur, adipiscing, elit,
|
||||
Vivamus, libero, massa, tincidunt, at, ex, nec, porta, malesuada,
|
||||
arcu, Nullam, lectus, nibh, dictum, eget, convallis, ac, feugiat,
|
||||
felis, Suspendisse, quis, purus, vel, lacus, cursus, tristique,
|
||||
Donec, augue, tortor, luctus, a, sed, mattis, in, quam, Cras, vitae,
|
||||
euismod, Cum, sociis, natoque, penatibus, et, magnis, dis,
|
||||
parturient)
|
||||
ENUM(Lipsum, int,
|
||||
Lorem, ipsum, dolor, sit, amet, consectetur, adipiscing, elit, Vivamus,
|
||||
libero, massa, tincidunt, at, ex, nec, porta, malesuada, arcu, Nullam,
|
||||
lectus, nibh, dictum, eget, convallis, ac, feugiat, felis, Suspendisse,
|
||||
quis, purus, vel, lacus, cursus, tristique, Donec, augue, tortor, luctus,
|
||||
a, sed, mattis, in, quam, Cras, vitae, euismod, Cum, sociis, natoque,
|
||||
penatibus, et, magnis, dis, parturient)
|
||||
|
||||
BETTER_ENUM(ASTNode0, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||
ENUM(ASTNode0, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
||||
BasicType, ArrowType, VariantTypeConstant)
|
||||
|
||||
BETTER_ENUM(ASTNode1, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||
ENUM(ASTNode1, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
||||
BasicType, ArrowType, VariantTypeConstant)
|
||||
|
||||
BETTER_ENUM(ASTNode2, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||
ENUM(ASTNode2, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
||||
BasicType, ArrowType, VariantTypeConstant)
|
||||
|
||||
BETTER_ENUM(ASTNode3, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||
ENUM(ASTNode3, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
||||
BasicType, ArrowType, VariantTypeConstant)
|
||||
|
||||
BETTER_ENUM(ASTNode4, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||
ENUM(ASTNode4, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
||||
BasicType, ArrowType, VariantTypeConstant)
|
||||
|
||||
BETTER_ENUM(ASTNode5, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||
ENUM(ASTNode5, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
||||
BasicType, ArrowType, VariantTypeConstant)
|
||||
|
||||
BETTER_ENUM(ASTNode6, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||
ENUM(ASTNode6, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
||||
BasicType, ArrowType, VariantTypeConstant)
|
||||
|
||||
BETTER_ENUM(ASTNode7, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||
ENUM(ASTNode7, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
||||
BasicType, ArrowType, VariantTypeConstant)
|
||||
|
||||
BETTER_ENUM(ASTNode8, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||
ENUM(ASTNode8, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
||||
BasicType, ArrowType, VariantTypeConstant)
|
||||
|
||||
BETTER_ENUM(ASTNode9, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||
ENUM(ASTNode9, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
||||
BasicType, ArrowType, VariantTypeConstant)
|
||||
|
||||
BETTER_ENUM(ASTNode10, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||
ENUM(ASTNode10, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
||||
BasicType, ArrowType, VariantTypeConstant)
|
||||
|
||||
BETTER_ENUM(ASTNode11, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||
ENUM(ASTNode11, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
||||
BasicType, ArrowType, VariantTypeConstant)
|
||||
|
||||
BETTER_ENUM(ASTNode12, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||
ENUM(ASTNode12, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
||||
BasicType, ArrowType, VariantTypeConstant)
|
||||
|
||||
BETTER_ENUM(ASTNode13, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||
ENUM(ASTNode13, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
||||
BasicType, ArrowType, VariantTypeConstant)
|
||||
|
||||
BETTER_ENUM(ASTNode14, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||
ENUM(ASTNode14, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
||||
BasicType, ArrowType, VariantTypeConstant)
|
||||
|
||||
BETTER_ENUM(ASTNode15, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||
ENUM(ASTNode15, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
||||
BasicType, ArrowType, VariantTypeConstant)
|
||||
|
||||
BETTER_ENUM(ASTNode16, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||
ENUM(ASTNode16, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
||||
BasicType, ArrowType, VariantTypeConstant)
|
||||
|
||||
BETTER_ENUM(ASTNode17, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||
ENUM(ASTNode17, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
||||
BasicType, ArrowType, VariantTypeConstant)
|
||||
|
||||
BETTER_ENUM(ASTNode18, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||
ENUM(ASTNode18, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
||||
BasicType, ArrowType, VariantTypeConstant)
|
||||
|
||||
BETTER_ENUM(ASTNode19, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||
ENUM(ASTNode19, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
||||
BasicType, ArrowType, VariantTypeConstant)
|
||||
|
||||
BETTER_ENUM(ASTNode20, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||
ENUM(ASTNode20, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
||||
BasicType, ArrowType, VariantTypeConstant)
|
||||
|
||||
BETTER_ENUM(ASTNode21, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||
ENUM(ASTNode21, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
||||
BasicType, ArrowType, VariantTypeConstant)
|
||||
|
||||
BETTER_ENUM(ASTNode22, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||
ENUM(ASTNode22, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
||||
BasicType, ArrowType, VariantTypeConstant)
|
||||
|
||||
BETTER_ENUM(ASTNode23, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||
ENUM(ASTNode23, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
||||
BasicType, ArrowType, VariantTypeConstant)
|
||||
|
||||
BETTER_ENUM(ASTNode24, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||
ENUM(ASTNode24, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
||||
BasicType, ArrowType, VariantTypeConstant)
|
||||
|
||||
BETTER_ENUM(ASTNode25, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||
ENUM(ASTNode25, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
||||
BasicType, ArrowType, VariantTypeConstant)
|
||||
|
||||
BETTER_ENUM(ASTNode26, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||
ENUM(ASTNode26, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
||||
BasicType, ArrowType, VariantTypeConstant)
|
||||
|
||||
BETTER_ENUM(ASTNode27, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||
ENUM(ASTNode27, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
||||
BasicType, ArrowType, VariantTypeConstant)
|
||||
|
||||
BETTER_ENUM(ASTNode28, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||
ENUM(ASTNode28, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
||||
BasicType, ArrowType, VariantTypeConstant)
|
||||
|
||||
BETTER_ENUM(ASTNode29, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||
ENUM(ASTNode29, int,
|
||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
||||
BasicType, ArrowType, VariantTypeConstant)
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
272
test/test.py
Executable file
272
test/test.py
Executable file
@ -0,0 +1,272 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
import glob
|
||||
import os
|
||||
import os.path
|
||||
import platform
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
|
||||
BASE_DIRECTORY = "platform"
|
||||
CXXTEST_SOURCE = "cxxtest/tests.h"
|
||||
CXXTEST_GENERATED = "cxxtest/tests.cc"
|
||||
|
||||
quiet = True
|
||||
windows = False
|
||||
|
||||
|
||||
|
||||
def file_title(path):
|
||||
return os.path.splitext(os.path.basename(path))[0]
|
||||
|
||||
|
||||
|
||||
expected_example_outputs = {}
|
||||
|
||||
def load_expected_outputs():
|
||||
files = glob.glob("expect/*")
|
||||
for file in files:
|
||||
stream = open(file)
|
||||
try:
|
||||
content = stream.read()
|
||||
finally:
|
||||
stream.close()
|
||||
|
||||
expected_example_outputs[file_title(file)] = content
|
||||
|
||||
|
||||
|
||||
def run(command, catch_warnings = False):
|
||||
if not quiet:
|
||||
print command
|
||||
|
||||
try:
|
||||
output = subprocess.check_output(command.split(),
|
||||
stderr = subprocess.STDOUT)
|
||||
|
||||
if not catch_warnings:
|
||||
return output
|
||||
else:
|
||||
if re.search("warning", output) != None:
|
||||
raise subprocess.CalledProcessError(0, command, output)
|
||||
return output
|
||||
|
||||
except subprocess.CalledProcessError as e:
|
||||
print e.output
|
||||
print command, "failed"
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
|
||||
class Configuration(object):
|
||||
def __init__(self, subdirectory, command, skip_examples = []):
|
||||
self._subdirectory = subdirectory
|
||||
self._command = command
|
||||
self._skip_examples = skip_examples
|
||||
|
||||
def elaborate(self, include, output, source):
|
||||
command = self._command
|
||||
if re.match("clang|[gc]\+\+", command) != None:
|
||||
return "%s -I%s -Wall -o %s %s" % (command, include, output, source)
|
||||
elif re.match("vc|cl", command) != None:
|
||||
return "%s /I%s /Fe%s %s" % (command, include, output, source)
|
||||
else:
|
||||
raise Exception("unrecognized compiler in '%s'" % command)
|
||||
|
||||
def make_directories(self):
|
||||
base = self.directory()
|
||||
directories = \
|
||||
[base,
|
||||
os.path.join(base, "example"),
|
||||
os.path.join(base, "cxxtest"),
|
||||
os.path.join(base, "link"),
|
||||
os.path.join(base, "performance")]
|
||||
|
||||
for directory in directories:
|
||||
if not os.path.lexists(directory):
|
||||
os.makedirs(directory)
|
||||
|
||||
def make_all(self):
|
||||
print self._command
|
||||
|
||||
self.make_directories()
|
||||
|
||||
base = self.directory()
|
||||
|
||||
examples = glob.glob("../example/*.cc")
|
||||
example_directory = os.path.join(base, "example")
|
||||
for file in examples:
|
||||
title = file_title(file)
|
||||
|
||||
if title in self._skip_examples:
|
||||
continue
|
||||
|
||||
if title not in expected_example_outputs:
|
||||
print "no expected output for example", title
|
||||
sys.exit(1)
|
||||
|
||||
binary = os.path.join(example_directory, title) + ".exe"
|
||||
|
||||
command = self.elaborate("..", binary, file)
|
||||
run(command, True)
|
||||
|
||||
output = run(binary)
|
||||
output = re.sub("\r\n", "\n", output)
|
||||
if output != expected_example_outputs[title]:
|
||||
print output
|
||||
print "output does not match expected output"
|
||||
sys.exit(1)
|
||||
|
||||
# This is currently not done on because on Cygwin, cxxtest tries to use
|
||||
# a Cygwin path to include tests.h. That path is in Unix format, which
|
||||
# does not resolve to a valid path when handled by VC++. A workaround is
|
||||
# to detect Cygwin and rewrite the path, but I am saving that for an
|
||||
# improved version of test.py, since there are many things that need to
|
||||
# be rewritten for this script to stay maintainable.
|
||||
if not windows:
|
||||
cxxtest_binary = os.path.join(base, "cxxtest", "tests.exe")
|
||||
command = self.elaborate("..", cxxtest_binary, CXXTEST_GENERATED)
|
||||
run(command, True)
|
||||
run(cxxtest_binary)
|
||||
|
||||
link_sources = glob.glob("link/*.cc")
|
||||
link_binary = os.path.join(base, "link", "link.exe")
|
||||
command = self.elaborate("..", link_binary, " ".join(link_sources))
|
||||
run(command, True)
|
||||
|
||||
performance_sources = glob.glob("performance/*.cc")
|
||||
performance_directory = os.path.join(base, "performance")
|
||||
for file in performance_sources:
|
||||
title = file_title(file)
|
||||
|
||||
binary = os.path.join(performance_directory, title) + ".exe"
|
||||
|
||||
command = "time " + self.elaborate("..", binary, file)
|
||||
output = run(command, True)
|
||||
|
||||
output_file = os.path.join(performance_directory, title) + ".times"
|
||||
stream = open(output_file, "w")
|
||||
try:
|
||||
stream.write(output)
|
||||
finally:
|
||||
stream.close()
|
||||
|
||||
def directory(self):
|
||||
return os.path.join(BASE_DIRECTORY, self._subdirectory)
|
||||
|
||||
|
||||
|
||||
skip_cxx98 = ["101-special-values", "102-bitset", "103-quine", "7-constexpr"]
|
||||
skip_strict = ["4-switch"]
|
||||
|
||||
def modern_gnu(command):
|
||||
return [
|
||||
Configuration(command + "-c++11", command + " -std=c++11"),
|
||||
Configuration(command + "-strict-conversion",
|
||||
command + " -std=c++11 " +
|
||||
"-DBETTER_ENUMS_STRICT_CONVERSION", skip_strict),
|
||||
Configuration(command + "-all-constexpr",
|
||||
command + " -std=c++11 " +
|
||||
"-DBETTER_ENUMS_CONSTEXPR_TO_STRING"),
|
||||
Configuration(command + "-c++98", command + " -std=c++98", skip_cxx98)
|
||||
]
|
||||
|
||||
# g++46 should be one of these, but g++46 c++11 mode currently not supported due
|
||||
# to the presence of this bug and lack of a workaround in enum.h.
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54086
|
||||
def older_gnu(command):
|
||||
return [
|
||||
Configuration(command + "-c++0x", command + " -std=c++0x"),
|
||||
Configuration(command + "-strict-conversion",
|
||||
command + " -std=c++0x " +
|
||||
"-DBETTER_ENUMS_STRICT_CONVERSION", skip_strict),
|
||||
Configuration(command + "-all-constexpr",
|
||||
command + " -std=c++0x " +
|
||||
"-DBETTER_ENUMS_CONSTEXPR_TO_STRING"),
|
||||
Configuration(command + "-c++98", command + " -std=c++98", skip_cxx98)
|
||||
]
|
||||
|
||||
def gnu_pre_constexpr(command):
|
||||
return [
|
||||
Configuration(command + "-c++0x-noconstexpr-war",
|
||||
command + " -std=c++0x " +
|
||||
"-DBETTER_ENUMS_NO_CONSTEXPR", skip_cxx98),
|
||||
Configuration(command + "-strict-conversion",
|
||||
command + " -std=c++0x " +
|
||||
"-DBETTER_ENUMS_NO_CONSTEXPR " +
|
||||
"-DBETTER_ENUMS_STRICT_CONVERSION",
|
||||
skip_cxx98 + skip_strict),
|
||||
Configuration(command + "-c++98", command + " -std=c++98", skip_cxx98)
|
||||
]
|
||||
|
||||
def gnu_pre_enum_class(command):
|
||||
return [
|
||||
Configuration(command + "-c++0x-noconstexpr-war",
|
||||
command + " -std=c++0x " +
|
||||
"-DBETTER_ENUMS_NO_CONSTEXPR", skip_cxx98),
|
||||
Configuration(command + "-c++98", command + " -std=c++98", skip_cxx98)
|
||||
]
|
||||
|
||||
def vc(command):
|
||||
return [
|
||||
Configuration(command, command + " /EHsc", skip_cxx98),
|
||||
Configuration(command + "-strict-conversion",
|
||||
command + " /EHsc /DBETTER_ENUMS_STRICT_CONVERSION",
|
||||
skip_cxx98)
|
||||
]
|
||||
|
||||
unix_configurations = \
|
||||
modern_gnu("clang++36") + \
|
||||
modern_gnu("clang++35") + \
|
||||
modern_gnu("clang++34") + \
|
||||
modern_gnu("clang++33") + \
|
||||
modern_gnu("g++51") + \
|
||||
modern_gnu("g++49") + \
|
||||
modern_gnu("g++48") + \
|
||||
modern_gnu("g++47") + \
|
||||
gnu_pre_constexpr("g++46") + \
|
||||
gnu_pre_constexpr("g++45") + \
|
||||
gnu_pre_constexpr("g++44") + \
|
||||
gnu_pre_enum_class("g++43")
|
||||
|
||||
windows_configurations = vc("vc2015") + vc("vc2013")
|
||||
|
||||
unix_default = Configuration("default", "c++ --std=c++11")
|
||||
|
||||
windows_default = Configuration("default", "cl /EHsc")
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
global quiet
|
||||
global windows
|
||||
|
||||
load_expected_outputs()
|
||||
|
||||
run("cxxtestgen --error-printer -o %s %s" %
|
||||
(CXXTEST_GENERATED, CXXTEST_SOURCE))
|
||||
|
||||
if re.search("Windows|CYGWIN", platform.system()) != None:
|
||||
full = windows_configurations
|
||||
default = windows_default
|
||||
windows = True
|
||||
else:
|
||||
full = unix_configurations
|
||||
default = unix_default
|
||||
|
||||
if len(sys.argv) > 1 and sys.argv[1] == "--all":
|
||||
configurations = full
|
||||
quiet = True
|
||||
else:
|
||||
configurations = [default]
|
||||
quiet = False
|
||||
|
||||
for configuration in configurations:
|
||||
configuration.make_all()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
x
Reference in New Issue
Block a user