mirror of
https://github.com/aantron/better-enums.git
synced 2025-12-07 01:06:42 +08:00
Compare commits
110 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
520d8ee390 | ||
|
|
d65550f378 | ||
|
|
1e8f499ddf | ||
|
|
f3ff0a6917 | ||
|
|
68ca02d1f5 | ||
|
|
517387fba0 | ||
|
|
fb8b398b02 | ||
|
|
c35576bed0 | ||
|
|
2422dd6f26 | ||
|
|
894eab5284 | ||
|
|
fd646ae537 | ||
|
|
abb693d4ef | ||
|
|
2f1fcaae7a | ||
|
|
3e115c0c17 | ||
|
|
c730fc8ae8 | ||
|
|
f480b7ef1c | ||
|
|
1a3c4f9e5a | ||
|
|
21c374914c | ||
|
|
dcbd3c0554 | ||
|
|
89bc057a63 | ||
|
|
5dcd59bd29 | ||
|
|
fa39f5c89e | ||
|
|
4b76e7783b | ||
|
|
1ea7f04bb9 | ||
|
|
e1756cdb07 | ||
|
|
5a677ac72b | ||
|
|
8a0d376b53 | ||
|
|
8b4d8a9499 | ||
|
|
ebc0c0138e | ||
|
|
b838852ff4 | ||
|
|
f626bcde1a | ||
|
|
509c544d0f | ||
|
|
ed21395b20 | ||
|
|
2d2a6a5648 | ||
|
|
882dd9cd1b | ||
|
|
94f8f95a26 | ||
|
|
df5df3924e | ||
|
|
97d38d8077 | ||
|
|
e5549fb18c | ||
|
|
21417b76b9 | ||
|
|
3558c94cc7 | ||
|
|
2fad3f60ee | ||
|
|
ecdc88f066 | ||
|
|
73a1619cb7 | ||
|
|
6988e0509e | ||
|
|
37d8f987ca | ||
|
|
ab4c8583db | ||
|
|
f520b397e3 | ||
|
|
c71b891c87 | ||
|
|
d94b21a7e0 | ||
|
|
9e522eaf3c | ||
|
|
18cbeb0808 | ||
|
|
2d6b337419 | ||
|
|
e6e8e24f5c | ||
|
|
a500851e28 | ||
|
|
cc9cce28ae | ||
|
|
9a754681c9 | ||
|
|
76ad2256dd | ||
|
|
f45897fcb3 | ||
|
|
472a33fb64 | ||
|
|
f148cc4314 | ||
|
|
e8d51bdd8e | ||
|
|
d99bae7284 | ||
|
|
e9b6792922 | ||
|
|
8061c24191 | ||
|
|
fc0b0de647 | ||
|
|
1620410372 | ||
|
|
9a2389cd15 | ||
|
|
c1d4a1c006 | ||
|
|
e1e237a4ea | ||
|
|
977f8ef145 | ||
|
|
0595a526e7 | ||
|
|
eac6afacdc | ||
|
|
0f816be0cd | ||
|
|
60a4f4dfda | ||
|
|
f404ea709b | ||
|
|
30efe7ccd7 | ||
|
|
6c3d02b951 | ||
|
|
f1a0b5d0e4 | ||
|
|
b182e16ec3 | ||
|
|
9273051e07 | ||
|
|
7cfd738c1a | ||
|
|
6278793a0b | ||
|
|
124c09f2f0 | ||
|
|
89a1c1a64b | ||
|
|
1769fbb6b7 | ||
|
|
07fef34465 | ||
|
|
3c3733c700 | ||
|
|
ba9139e075 | ||
|
|
535f7f151b | ||
|
|
54b7a054be | ||
|
|
faf3676fec | ||
|
|
9a02379937 | ||
|
|
f5f669277a | ||
|
|
d90bfd6f18 | ||
|
|
9810dd07ce | ||
|
|
aa34aad468 | ||
|
|
a493e90ac4 | ||
|
|
fc609e58aa | ||
|
|
74b3a66284 | ||
|
|
98232ee4fb | ||
|
|
7502ae3c18 | ||
|
|
11a1c26494 | ||
|
|
0f63667106 | ||
|
|
4314ad3fd3 | ||
|
|
b037d8b5eb | ||
|
|
5edcb3e121 | ||
|
|
97197088fe | ||
|
|
820fd22b5f | ||
|
|
41508fb114 |
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -1,2 +0,0 @@
|
|||||||
*.h linguist-language=C++
|
|
||||||
*.tmpl linguist-language=HTML
|
|
||||||
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
github: aantron
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@ -5,4 +5,4 @@ scratch/
|
|||||||
doc/html/
|
doc/html/
|
||||||
doc-publish/
|
doc-publish/
|
||||||
test/cxxtest/*.cc
|
test/cxxtest/*.cc
|
||||||
test/platform/
|
test/build
|
||||||
|
|||||||
38
.travis.yml
Normal file
38
.travis.yml
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
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-2015, Anton Bachin
|
Copyright (c) 2012-2024, Anton Bachin
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without modification,
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
119
README.md
119
README.md
@ -1,39 +1,21 @@
|
|||||||
# Better Enums
|
# Better Enums [![Try online][wandbox-img]][wandbox] [![Travis status][travis-img]][travis] [![AppVeyor status][appveyor-img]][appveyor]
|
||||||
|
|
||||||
Reflective compile-time C++ enum library with clean syntax, in a single header
|
[wandbox]: http://melpon.org/wandbox/permlink/2QCi3cwQnplAToge
|
||||||
file. For example:
|
[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
|
||||||
|
|
||||||
#include <enum.h>
|
Reflective compile-time enum library with clean syntax, in a single header
|
||||||
ENUM(Channel, int, Red = 1, Green, Blue)
|
file, and without dependencies.
|
||||||
|
|
||||||
defines a type `Channel`. You can then do natural things such as:
|
![Better Enums code overview][sample]
|
||||||
|
|
||||||
```cpp
|
[sample]: https://raw.githubusercontent.com/aantron/better-enums/master/doc/image/sample.gif
|
||||||
Channel channel = Channel::Green;
|
|
||||||
|
|
||||||
channel._to_string(); // Results in the string "Green"
|
In C++11, *everything* can be used at compile time. You can convert your enums,
|
||||||
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],
|
loop over them, [find their max][max],
|
||||||
[statically enforce conventions][enforce], and pass along the results as
|
[statically enforce conventions][enforce], and pass along the results as
|
||||||
template arguments or to `constexpr` functions. All the reflection is available
|
template arguments or to `constexpr` functions. All the reflection is available
|
||||||
@ -49,36 +31,73 @@ See the [project page][project] for full documentation.
|
|||||||
[enforce]: http://aantron.github.io/better-enums/demo/SpecialValues.html
|
[enforce]: http://aantron.github.io/better-enums/demo/SpecialValues.html
|
||||||
[project]: http://aantron.github.io/better-enums
|
[project]: http://aantron.github.io/better-enums
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
Simply add `enum.h` to your project — that's it.
|
Simply add `enum.h` to your project.
|
||||||
|
|
||||||
Then, include it and use the `ENUM` macro. Your compiler will generate the rich
|
<br/>
|
||||||
enums that are missing from standard C++.
|
|
||||||
|
|
||||||
## Additional features
|
## Additional features
|
||||||
|
|
||||||
- No dependencies and no external build tools. Uses only standard C++, though,
|
- Uses only standard C++, though, for C++98, variadic macro support is required
|
||||||
for C++98, variadic macro support is required.
|
(major compilers have it).
|
||||||
- Supported and tested on clang, gcc, and msvc.
|
- Supported and tested on [clang, gcc, and msvc][testing].
|
||||||
- Fast compilation. You have to declare a few dozen enums to slow down your
|
- Fast compilation. You have to declare a few dozen enums to slow down your
|
||||||
compiler as much as [just including `iostream` does][performance].
|
compiler as much as [only including `iostream` does][performance].
|
||||||
- Use any initializers, just like with a built-in enum.
|
- Use any initializers and sparse ranges, just like with a built-in enum.
|
||||||
- Guaranteed size and alignment — you choose the representation type.
|
- 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.
|
||||||
|
|
||||||
|
[testing]: http://aantron.github.io/better-enums/CompilerSupport.html
|
||||||
[performance]: http://aantron.github.io/better-enums/Performance.html
|
[performance]: http://aantron.github.io/better-enums/Performance.html
|
||||||
|
|
||||||
## Contact
|
<br/>
|
||||||
|
|
||||||
Don't hesitate to contact me about features or bugs:
|
## Limitations
|
||||||
[antonbachin@yahoo.com](mailto:antonbachin@yahoo.com), or open an issue on
|
|
||||||
GitHub.
|
|
||||||
|
|
||||||
## License and history
|
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`):
|
||||||
|
|
||||||
Better Enums is released under the BSD 2-clause license. See
|
```c++
|
||||||
[LICENSE](https://github.com/aantron/better-enums/blob/master/LICENSE).
|
BETTER_ENUM(SomePrefix_Color, uint8_t, Red, Green, Blue)
|
||||||
|
|
||||||
The library was originally developed by the author in the winter of 2012-2013 at
|
struct triplet {
|
||||||
Hudson River Trading, as a replacement for an older generator called
|
typedef SomePrefix_Color Color;
|
||||||
`BETTER_ENUM`.
|
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`.
|
||||||
|
|||||||
29
appveyor.yml
Normal file
29
appveyor.yml
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
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
|
The declaration
|
||||||
|
|
||||||
#include <enum.h>
|
#include <enum.h>
|
||||||
<em>ENUM</em>(<em>Enum</em>, <em>underlying_type</em>, <em>A</em>, <em>B</em>, <em>C</em>, ...)
|
<em>BETTER_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
|
generates a new class type `Enum` which is notionally similar to the type
|
||||||
created by this $cxx11 declaration:
|
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`.
|
`Enum::C`, and so on, with memory representation the same as `underlying_type`.
|
||||||
It is possible to supply initializers for any of the constants:
|
It is possible to supply initializers for any of the constants:
|
||||||
|
|
||||||
<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>, ...)
|
<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>, ...)
|
||||||
|
|
||||||
The initializers have the same meaning and constraints as in a built-in `enum`
|
The initializers have the same meaning and constraints as in a built-in `enum`
|
||||||
or `enum class` declaration.
|
or `enum class` declaration.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
The principal differences between the types declared by the `ENUM` macro and
|
The principal differences between the types declared by the `BETTER_ENUM` macro
|
||||||
`enum class` are:
|
and `enum class` are:
|
||||||
|
|
||||||
- `ENUM` is available for $cxx98
|
- `BETTER_ENUM` is available for $cxx98
|
||||||
[compilers](${prefix}CompilerSupport.html) supporting `__VA_ARGS__` —
|
[compilers](${prefix}CompilerSupport.html) supporting `__VA_ARGS__` —
|
||||||
all major compilers — while `enum class` is restricted to $cxx11,
|
all major compilers — while `enum class` is restricted to $cxx11,
|
||||||
- the `ENUM` type is implicitly convertible to integral types, though this can
|
- the `BETTER_ENUM` type is implicitly convertible to integral types, though
|
||||||
be [disabled](${prefix}OptInFeatures.html#StrictConversions) when using
|
this can be [disabled](${prefix}OptInFeatures.html#StrictConversions) when
|
||||||
$cxx11, and
|
using $cxx11, and
|
||||||
- the `ENUM` type supports a set of reflective operations, detailed in the
|
- the `BETTER_ENUM` type supports a set of reflective operations, detailed in
|
||||||
rest of this reference.
|
the rest of this reference.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
The types produced by the `ENUM` macro are called *Better Enums* in the rest of
|
The types produced by the `BETTER_ENUM` macro are called *Better Enums* in the
|
||||||
this reference.
|
rest of this reference.
|
||||||
|
|
||||||
Better Enums are similar to their underlying type for the purposes of argument
|
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
|
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:
|
The rest of this reference uses the following declaration as a running example:
|
||||||
|
|
||||||
<em>ENUM</em>(<em>Enum</em>, <em>int</em>, <em>A</em>, <em>B</em>, <em>C</em>)
|
<em>BETTER_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>
|
#### <em>typedef _enumerated</em>
|
||||||
|
|
||||||
An internal type used to declare constants. The `ENUM` macro generates something
|
An internal type used to declare constants. The `BETTER_ENUM` macro generates
|
||||||
similar to
|
something similar to
|
||||||
|
|
||||||
~~~comment
|
~~~comment
|
||||||
<em>struct Enum</em> {
|
<em>struct Enum</em> {
|
||||||
@ -150,9 +150,14 @@ 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
|
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).
|
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`.
|
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.
|
||||||
|
|
||||||
#### <em>typedef _value_iterable</em>
|
#### <em>typedef _value_iterable</em>
|
||||||
|
|
||||||
@ -223,7 +228,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
|
constant. Otherwise, throws `std::runtime_error`. Running time is linear in the
|
||||||
number of declared constants multiplied by the length of the longest constant.
|
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
|
Same as [`_from_string`](#_from_string), but does not throw an exception on
|
||||||
failure. Returns an [optional value](#StructBetter_enumsoptional) instead.
|
failure. Returns an [optional value](#StructBetter_enumsoptional) instead.
|
||||||
@ -233,7 +238,7 @@ failure. Returns an [optional value](#StructBetter_enumsoptional) instead.
|
|||||||
Same as [`_from_string`](#_from_string), but comparison is up to case, in the
|
Same as [`_from_string`](#_from_string), but comparison is up to case, in the
|
||||||
usual sense in the Latin-1 encoding.
|
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
|
Is to [`_from_string_nocase`](#_from_string_nocase) as
|
||||||
[`_from_string_nothrow`](#_from_string_nothrow) is to
|
[`_from_string_nothrow`](#_from_string_nothrow) is to
|
||||||
@ -255,7 +260,7 @@ case as in [`_from_string_nocase`](#_from_string_nocase).
|
|||||||
Evaluates to the name of the Better Enum type. `Enum::_name()` is the same
|
Evaluates to the name of the Better Enum type. `Enum::_name()` is the same
|
||||||
string as `"Enum"`.
|
string as `"Enum"`.
|
||||||
|
|
||||||
#### typedef <em>_name_iterable</em>
|
#### <em>typedef _name_iterable</em>
|
||||||
|
|
||||||
Type of object that permits iteration over names of declared constants. Has at
|
Type of object that permits iteration over names of declared constants. Has at
|
||||||
least `constexpr` `begin()`, `end()`, and `size()` methods. `operator[]` is also
|
least `constexpr` `begin()`, `end()`, and `size()` methods. `operator[]` is also
|
||||||
@ -263,7 +268,7 @@ available, but is `constexpr` if and only if [`_to_string`](#_to_string) is
|
|||||||
`constexpr`. Iteration visits constants in order of declaration. See usage
|
`constexpr`. Iteration visits constants in order of declaration. See usage
|
||||||
example under [`_names`](#_names).
|
example under [`_names`](#_names).
|
||||||
|
|
||||||
#### typedef <em>_name_iterator</em>
|
#### <em>typedef _name_iterator</em>
|
||||||
|
|
||||||
Random-access iterator type for `_name_iterable`. Most operations are
|
Random-access iterator type for `_name_iterable`. Most operations are
|
||||||
`constexpr`, but dereferencing is `constexpr` if and only if
|
`constexpr`, but dereferencing is `constexpr` if and only if
|
||||||
@ -322,7 +327,7 @@ example,
|
|||||||
(+<em>Enum::C</em>)<em>._to_integral</em>() == <em>2</em>
|
(+<em>Enum::C</em>)<em>._to_integral</em>() == <em>2</em>
|
||||||
|
|
||||||
Note that Better Enums are already implicitly convertible to their underlying
|
Note that Better Enums are already implicitly convertible to their underlying
|
||||||
integral types [by default](${prefix}OptInFeatures.html#StrictConversion).
|
integral types [by default](${prefix}OptInFeatures.html#StrictConversions).
|
||||||
You may still want to use this function, however, for clarity, and to ensure
|
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
|
that your code remains compatible if the strict conversions feature is enabled
|
||||||
later.
|
later.
|
||||||
@ -337,7 +342,7 @@ of one of the declared constants.
|
|||||||
<em>Enum::_from_integral</em>(<em>2</em>); // Enum::C
|
<em>Enum::_from_integral</em>(<em>2</em>); // Enum::C
|
||||||
<em>Enum::_from_integral</em>(<em>42</em>); // std::runtime_error
|
<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
|
Checked conversion as [`_from_integral`](#_from_integral), but does not throw an
|
||||||
exception on failure. Returns an [optional value](#StructBetter_enumsoptional)
|
exception on failure. Returns an [optional value](#StructBetter_enumsoptional)
|
||||||
@ -365,6 +370,64 @@ 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
|
%% class = api
|
||||||
|
|
||||||
%% description = Detailed description of the Better Enums API.
|
%% description = Detailed description of the Better Enums API.
|
||||||
|
|||||||
94
doc/CONTRIBUTING.md
Normal file
94
doc/CONTRIBUTING.md
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
# 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`.
|
||||||
11
doc/CONTRIBUTORS
Normal file
11
doc/CONTRIBUTORS
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
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,11 +1,10 @@
|
|||||||
## Compiler support
|
## Compiler support
|
||||||
|
|
||||||
Better Enums aims to support all major compilers. It is known to definitely work
|
Better Enums aims to support all major compilers. It is known to work on:
|
||||||
on
|
|
||||||
|
|
||||||
- clang 3.3 to 3.6
|
- clang 3.3 to 3.9
|
||||||
- gcc 4.3 to 5.1
|
- gcc 4.3 to 5.3
|
||||||
- Visual C++ 2013U4, 2015RC.
|
- Visual C++ 2008 to 2015.
|
||||||
|
|
||||||
The library can be used with any compiler that supports either $cxx11, or $cxx98
|
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
|
with the `__VA_ARGS__` extension. This includes every version of gcc and clang I
|
||||||
@ -76,6 +75,21 @@ vc2015 /EHsc
|
|||||||
vc2015 /EHsc /DBETTER_ENUMS_STRICT_CONVERSION
|
vc2015 /EHsc /DBETTER_ENUMS_STRICT_CONVERSION
|
||||||
vc2013 /EHsc
|
vc2013 /EHsc
|
||||||
vc2013 /EHsc /DBETTER_ENUMS_STRICT_CONVERSION
|
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
|
||||||
clang++36 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
|
clang++36 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
|
||||||
clang++36 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
|
clang++36 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
|
||||||
@ -88,14 +102,11 @@ clang++34 -std=c++11
|
|||||||
clang++34 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
|
clang++34 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
|
||||||
clang++34 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
|
clang++34 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
|
||||||
clang++34 -std=c++98
|
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
|
clang++33 -std=c++98
|
||||||
g++51 -std=c++11
|
g++53 -std=c++11
|
||||||
g++51 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
|
g++53 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
|
||||||
g++51 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
|
g++53 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
|
||||||
g++51 -std=c++98
|
g++53 -std=c++98
|
||||||
g++49 -std=c++11
|
g++49 -std=c++11
|
||||||
g++49 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
|
g++49 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
|
||||||
g++49 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
|
g++49 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
|
||||||
@ -108,17 +119,12 @@ g++47 -std=c++11
|
|||||||
g++47 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
|
g++47 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
|
||||||
g++47 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
|
g++47 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
|
||||||
g++47 -std=c++98
|
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++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++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++44 -std=c++98
|
||||||
g++43 -std=c++0x -DBETTER_ENUMS_NO_CONSTEXPR
|
|
||||||
g++43 -std=c++98
|
g++43 -std=c++98
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
%% description = Information about compiler support and feature detection.
|
%% description =
|
||||||
|
Better Enums compiler support, compatibility, feature detection, and automated
|
||||||
|
testing.
|
||||||
|
|||||||
@ -1,15 +0,0 @@
|
|||||||
## 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.
|
|
||||||
269
doc/DesignDecisionsFAQ.md
Normal file
269
doc/DesignDecisionsFAQ.md
Normal file
@ -0,0 +1,269 @@
|
|||||||
|
## 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
|
## Extending limits
|
||||||
|
|
||||||
The `ENUM` macro makes heavy use of the preprocessor, and some of the internal
|
The `BETTER_ENUM` macro makes heavy use of the preprocessor, and some of the
|
||||||
macros have size limits. There are two: on the number of constants you can
|
internal macros have size limits. There are two: on the number of constants you
|
||||||
declare, and on the maximum length of a constant name under very specific
|
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
|
conditions. If you run into either one, you can extend the limit by following
|
||||||
the instructions on this page.
|
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
|
example. Add 1 to the number of characters to account for the null
|
||||||
terminator — our numbers are now 512 and 64.
|
terminator — our numbers are now 512 and 64.
|
||||||
2. Get `make_macros.py` from your copy of the full Better Enums distribution
|
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/$version/script/make_macros.py" download>GitHub</a>.
|
or from <a href="https://raw.githubusercontent.com/aantron/better-enums/$ref/script/make_macros.py" download>GitHub</a>.
|
||||||
3. You will run this script to generate a header file containing some
|
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
|
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
|
location somewhere in your include path. I will assume that this file is
|
||||||
@ -31,10 +31,38 @@ constants of full-`constexpr` enums. To extend:
|
|||||||
|
|
||||||
- For g++ and clang++, `-DBETTER_ENUMS_MACRO_FILE='<common/enum_macros.h>'`
|
- For g++ and clang++, `-DBETTER_ENUMS_MACRO_FILE='<common/enum_macros.h>'`
|
||||||
- For VC++, `\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
|
6. Enjoy the looser limits. Just watch out — increasing the second
|
||||||
number can really slow down compilation of full-`constexpr` enums.
|
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
|
7. You don't need `make_macros.py` anymore. It's not part of your build
|
||||||
process and you can delete it.
|
process and you can delete it.
|
||||||
|
|
||||||
%% description = How to extend limits imposed by internal macros.
|
---
|
||||||
|
|
||||||
|
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.
|
||||||
|
|||||||
35
doc/Makefile
35
doc/Makefile
@ -1,23 +1,36 @@
|
|||||||
SOURCE_MARKDOWN := $(wildcard tutorial/*) $(wildcard demo/*)
|
toexample = ../example/$(notdir $(1:.md=.cc))
|
||||||
SOURCE_CXX := $(SOURCE_MARKDOWN:.md=.cc)
|
|
||||||
|
|
||||||
.PHONY : all
|
SOURCE_MARKDOWN := $(wildcard tutorial/*.md) $(wildcard demo/*.md)
|
||||||
all : html examples
|
SOURCE_CXX := $(foreach md,$(SOURCE_MARKDOWN),$(call toexample,$(md)))
|
||||||
|
|
||||||
.PHONY : html
|
.PHONY : html
|
||||||
html :
|
html :
|
||||||
python docs.py
|
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
|
.PHONY : examples
|
||||||
examples : clean-examples $(SOURCE_CXX)
|
examples : $(SOURCE_CXX)
|
||||||
|
|
||||||
.PHONY : clean-examples
|
define EXAMPLE
|
||||||
clean-examples :
|
$(1) : $(2)
|
||||||
make -C ../example clean
|
python transform.py --o-cxx $(1) $(2)
|
||||||
rm -f ../example/*.cc
|
endef
|
||||||
|
|
||||||
%.cc : %.md
|
$(foreach md,$(SOURCE_MARKDOWN), \
|
||||||
python transform.py --o-cxx ../example/$(notdir $@) $<
|
$(eval $(call EXAMPLE,$(call toexample,$(md)),$(md))))
|
||||||
|
|
||||||
.PHONY : clean
|
.PHONY : clean
|
||||||
clean :
|
clean :
|
||||||
|
|||||||
@ -6,6 +6,27 @@ default. Read this page if you want to enable them.
|
|||||||
|
|
||||||
$internal_toc
|
$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
|
### Compile-time name trimming
|
||||||
|
|
||||||
This makes `_to_string` and `_names` `constexpr`, i.e. "full" `constexpr` mode.
|
This makes `_to_string` and `_names` `constexpr`, i.e. "full" `constexpr` mode.
|
||||||
@ -22,7 +43,8 @@ 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
|
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
|
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
|
point where compile-time name trimming can be the default, I will simply
|
||||||
redefine `SLOW_ENUM` as `ENUM` and deprecate it, so your code will still work.
|
redefine `SLOW_ENUM` as `BETTER_ENUM` and deprecate it, so your code will still
|
||||||
|
work.
|
||||||
|
|
||||||
### Strict conversions
|
### Strict conversions
|
||||||
|
|
||||||
@ -64,5 +86,17 @@ Here they are:
|
|||||||
case <em>+</em>Channel::Blue: break;
|
case <em>+</em>Channel::Blue: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
%% description = Opting into features disabled by default for performance or
|
%% description = Optional Better Enums features, disabled by default for
|
||||||
compatibility reasons.
|
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> {
|
||||||
|
|||||||
@ -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:
|
The files compared in the test are as follows:
|
||||||
|
|
||||||
- [One file]($repo/blob/$version/test/performance/4-declare_enums.cc) includes
|
- [One file]($repo/blob/$ref/test/performance/4-declare_enums.cc) includes
|
||||||
`enum.h` and declares 647 constants across 36 Better Enums.
|
`enum.h` and declares 647 constants across 36 Better Enums.
|
||||||
- The [other file]($repo/blob/$version/test/performance/5-iostream.cc) *only*
|
- The [other file]($repo/blob/$ref/test/performance/5-iostream.cc) *only*
|
||||||
includes `iostream` and does nothing with it.
|
includes `iostream` and does nothing with it.
|
||||||
|
|
||||||
The argument is that if compiling a bunch of Better Enums is faster, or about as
|
The argument is that if compiling a bunch of Better Enums is faster, or about as
|
||||||
@ -29,4 +29,22 @@ compiled faster.
|
|||||||
- gcc 5.1, full `constexpr`: 4.23
|
- gcc 5.1, full `constexpr`: 4.23
|
||||||
- VC2015RC, $cxx98: 1.18
|
- VC2015RC, $cxx98: 1.18
|
||||||
|
|
||||||
%% description = Compilation performance testing results.
|
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.
|
||||||
|
|||||||
@ -11,13 +11,19 @@ pre, code, samp, h4, .contents ul {
|
|||||||
Consolas, "Liberation Mono", Menlo, "Courier New", Courier, monospace;
|
Consolas, "Liberation Mono", Menlo, "Courier New", Courier, monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h1, .splash-text .self, nav .self {
|
||||||
|
font-family: Georgia, Times, "Times New Roman", serif;
|
||||||
|
}
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
background-color: #477093;
|
background-color: #477093;
|
||||||
padding: 1.5em 20px;
|
padding: 1.5em 20px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
overflow: scroll;
|
overflow: auto;
|
||||||
color: rgba(255, 255, 255, 0.6);
|
color: rgba(255, 255, 255, 0.6);
|
||||||
font-size: 78%;
|
font-size: 78%;
|
||||||
|
max-width: 84ex;
|
||||||
|
margin-left: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
pre em {
|
pre em {
|
||||||
@ -45,21 +51,35 @@ code, samp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
max-width: 760px;
|
margin-left: 150px;
|
||||||
margin-left: 230px;
|
margin-right: 150px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 1220px) {
|
.main .container > * {
|
||||||
|
max-width: 41em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.index .main .container > * {
|
||||||
|
max-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main .container > .contents {
|
||||||
|
max-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1400px) {
|
||||||
.container {
|
.container {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
|
width: 1100px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 780px) {
|
@media (max-width: 1120px) {
|
||||||
.container {
|
.container {
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
|
width: auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,6 +99,17 @@ nav, .spacer {
|
|||||||
background-color: #222;
|
background-color: #222;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nav > * > span {
|
||||||
|
float: right;
|
||||||
|
opacity: 0.9;
|
||||||
|
margin-right: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav .self {
|
||||||
|
font-size: 16px;
|
||||||
|
padding-right: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
nav a {
|
nav a {
|
||||||
margin-right: 2em;
|
margin-right: 2em;
|
||||||
}
|
}
|
||||||
@ -103,13 +134,38 @@ header {
|
|||||||
background: linear-gradient(#395E7E, #4A79A0);
|
background: linear-gradient(#395E7E, #4A79A0);
|
||||||
color: white;
|
color: white;
|
||||||
padding: 50px 0;
|
padding: 50px 0;
|
||||||
margin-bottom: 50px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 60px;
|
font-size: 60px;
|
||||||
font-weight: 100;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
header h2 {
|
header h2 {
|
||||||
@ -129,10 +185,41 @@ header h3 {
|
|||||||
opacity: 0.5;
|
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 {
|
h2 {
|
||||||
margin-top: 2em;
|
margin-top: 2em;
|
||||||
font-size: 36px;
|
font-size: 36px;
|
||||||
font-weight: 100;
|
font-weight: 300;
|
||||||
}
|
}
|
||||||
|
|
||||||
hr {
|
hr {
|
||||||
@ -142,20 +229,20 @@ hr {
|
|||||||
|
|
||||||
footer {
|
footer {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
margin-top: 150px;
|
margin-top: 100px;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
opacity: 0.6;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: white;
|
color: white;
|
||||||
background-color: red;
|
/*background-color: red;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
a[href=""] {
|
a[href=""] {
|
||||||
color: white !important;
|
color: white !important;
|
||||||
background-color: red !important;
|
/*background-color: red !important;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
a:hover {
|
a:hover {
|
||||||
@ -166,6 +253,10 @@ header a:hover {
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.main {
|
||||||
|
margin-top: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
.main a[href], footer a[href] {
|
.main a[href], footer a[href] {
|
||||||
background-color: #edd;
|
background-color: #edd;
|
||||||
color: #844;
|
color: #844;
|
||||||
@ -215,7 +306,6 @@ span#note:target {
|
|||||||
|
|
||||||
.main h3 {
|
.main h3 {
|
||||||
font-size: 30px;
|
font-size: 30px;
|
||||||
font-weight: 100;
|
|
||||||
margin-top: 2em;
|
margin-top: 2em;
|
||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
@ -288,15 +378,45 @@ li {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.blurbs > li {
|
.blurbs > li {
|
||||||
width: 45%;
|
|
||||||
float: left;
|
float: left;
|
||||||
min-height: 5em;
|
min-height: 5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.blurbs > li.even {
|
@media (min-width: 1076px) {
|
||||||
|
.blurbs > li {
|
||||||
|
width: 28%;
|
||||||
|
margin-right: 4%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blurbs > li.zero-mod-three {
|
||||||
clear: both;
|
clear: both;
|
||||||
margin-left: 3%;
|
margin-left: 2%;
|
||||||
margin-right: 6%;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.blurbs strong {
|
.blurbs strong {
|
||||||
@ -311,19 +431,6 @@ li {
|
|||||||
font-style: normal;
|
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 {
|
.act strong {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 120%;
|
font-size: 120%;
|
||||||
@ -342,9 +449,25 @@ li {
|
|||||||
padding-left: 25px;
|
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 {
|
.splash {
|
||||||
|
float: right;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-left: -10%;
|
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -354,12 +477,22 @@ li {
|
|||||||
|
|
||||||
.splash pre.left {
|
.splash pre.left {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
color: inherit;
|
color: black;
|
||||||
|
font-weight: bold;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
|
padding-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.splash pre.right {
|
.splash pre.right {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1000px) {
|
||||||
|
.splash {
|
||||||
|
float: none;
|
||||||
|
margin-left: -10%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 700px) {
|
@media (max-width: 700px) {
|
||||||
@ -385,6 +518,7 @@ h4 {
|
|||||||
color: #888;
|
color: #888;
|
||||||
padding-top: 1em;
|
padding-top: 1em;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
font-size: 125%;
|
||||||
}
|
}
|
||||||
|
|
||||||
h4 em {
|
h4 em {
|
||||||
@ -394,9 +528,9 @@ h4 em {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.api ul.contents {
|
.api ul.contents {
|
||||||
-webkit-columns: 300px 2;
|
-webkit-columns: 300px 3;
|
||||||
-moz-columns: 300px 2;
|
-moz-columns: 300px 3;
|
||||||
columns: 300px 2;
|
columns: 300px 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.api ul.contents > li {
|
.api ul.contents > li {
|
||||||
@ -407,6 +541,7 @@ h4 em {
|
|||||||
|
|
||||||
.main h3 {
|
.main h3 {
|
||||||
margin-top: 4em;
|
margin-top: 4em;
|
||||||
|
clear: both;
|
||||||
}
|
}
|
||||||
|
|
||||||
h3.contents {
|
h3.contents {
|
||||||
@ -425,3 +560,36 @@ h3.contents {
|
|||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
padding-bottom: 1em;
|
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:
|
Now, we can declare enums like these:
|
||||||
|
|
||||||
ENUM(<em>Channel</em>, int, Red, Green, Blue, <em>Invalid</em>)
|
BETTER_ENUM(<em>Channel</em>, int, Red, Green, Blue, <em>Invalid</em>)
|
||||||
// Invalid is the invalid value by default
|
// Invalid is the invalid value by default
|
||||||
|
|
||||||
ENUM(<em>Compression</em>, int, <em>Undefined</em>, None, Huffman)
|
BETTER_ENUM(<em>Compression</em>, int, <em>Undefined</em>, None, Huffman)
|
||||||
OVERRIDE_INVALID(<em>Compression</em>, <em>Undefined</em>)
|
OVERRIDE_INVALID(<em>Compression</em>, <em>Undefined</em>)
|
||||||
|
|
||||||
and use them:
|
and use them:
|
||||||
@ -71,7 +71,7 @@ slightly more complex template function for the general case:
|
|||||||
constexpr <em>Enum default_imp</em>l()
|
constexpr <em>Enum default_imp</em>l()
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
<em>Enum::_size < 2 ?
|
<em>Enum::_size() < 2 ?
|
||||||
throw std::logic_error("enum has no valid constants") :
|
throw std::logic_error("enum has no valid constants") :
|
||||||
Enum::_values()[0] == invalid_impl<Enum>() ?
|
Enum::_values()[0] == invalid_impl<Enum>() ?
|
||||||
Enum::_values()[1] :
|
Enum::_values()[1] :
|
||||||
@ -100,7 +100,7 @@ And, as before, the usage:
|
|||||||
|
|
||||||
And, if you do
|
And, if you do
|
||||||
|
|
||||||
ENUM(<em>Answer</em>, int, Yes, No, <em>Invalid</em>)
|
BETTER_ENUM(<em>Answer</em>, int, Yes, No, <em>Invalid</em>)
|
||||||
// OVERRIDE_DEFAULT(<em>Answer</em>, <em>Invalid</em>)
|
// OVERRIDE_DEFAULT(<em>Answer</em>, <em>Invalid</em>)
|
||||||
|
|
||||||
you will get a helpful compile-time error saying
|
you will get a helpful compile-time error saying
|
||||||
@ -170,5 +170,6 @@ 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.
|
can be encoded in a reasonable fashion using the tools Better Enums provides.
|
||||||
Enjoy!
|
Enjoy!
|
||||||
|
|
||||||
%% description = Encoding project policies for static enforcement using Better
|
%% description = An example that uses Better Enums compile-time reflection to
|
||||||
Enums.
|
create invalid and default values for each enum, enforced statically by the
|
||||||
|
compiler, for readability and maintainability.
|
||||||
|
|||||||
@ -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)
|
constexpr <em>Enum max_loop</em>(Enum accumulator, size_t index)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
<em>index >= Enum::_size ? accumulator :
|
<em>index >= Enum::_size() ? accumulator :
|
||||||
Enum::_values()[index] > accumulator ?
|
Enum::_values()[index] > accumulator ?
|
||||||
max_loop<Enum>(Enum::_values()[index], index + 1) :
|
max_loop<Enum>(Enum::_values()[index], index + 1) :
|
||||||
max_loop<Enum>(accumulator, index + 1)</em>;
|
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
|
declared. We just declare enums, and the numeric values of their constants will
|
||||||
be bit indices. The rest is straightforward.
|
be bit indices. The rest is straightforward.
|
||||||
|
|
||||||
ENUM(<em>EFLAGS</em>, int,
|
BETTER_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>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>Overflow</em>, <em>NestedTask</em> = 14, <em>Resume</em> = 16, <em>V8086</em>, <em>AlignmentCheck</em>,
|
||||||
<em>CPUIDPresent</em> = 21)
|
<em>CPUIDPresent</em> = 21)
|
||||||
@ -65,5 +65,5 @@ static_assert(max<EFLAGS>()._to_integral() < 32,
|
|||||||
"some bit indices are out of range");
|
"some bit indices are out of range");
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
%% description = Finding the maximum value of a Better Enum constant for use in
|
%% description = Finding the maximum value of a Better Enum for use in declaring
|
||||||
declaring bit set types.
|
statically-sized 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
|
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
|
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
|
dump the definition than shown here. You could simply define a macro that
|
||||||
expands to an `ENUM` declaration and also stringizes it.
|
expands to an `BETTER_ENUM` declaration and also stringizes it.
|
||||||
|
|
||||||
But that's not the point here. The point of this page is to show some of the
|
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
|
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:
|
Now, let's declare some enums to dump later:
|
||||||
|
|
||||||
ENUM(<em>Channel</em>, int, Red, Green, Blue)
|
BETTER_ENUM(<em>Channel</em>, int, Red, Green, Blue)
|
||||||
ENUM(<em>Depth</em>, int, TrueColor = 1, HighColor = 0)
|
BETTER_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)
|
constexpr <em>size_t constants_length</em>(size_t index = 0, size_t accumulator = 0)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
<em>index >= Enum::_size ? accumulator :
|
<em>index >= Enum::_size() ? accumulator :
|
||||||
constants_length<Enum>(
|
constants_length<Enum>(
|
||||||
index + 1, accumulator
|
index + 1, accumulator
|
||||||
+ string_length(", ")
|
+ string_length(", ")
|
||||||
@ -102,7 +102,7 @@ the whole enum:
|
|||||||
constexpr <em>size_t declaration_length</em>()
|
constexpr <em>size_t declaration_length</em>()
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
<em>string_length("ENUM(")
|
<em>string_length("BETTER_ENUM(")
|
||||||
+ string_length(Enum::_name())
|
+ string_length(Enum::_name())
|
||||||
+ string_length(", int")
|
+ string_length(", int")
|
||||||
+ constants_length<Enum>()
|
+ constants_length<Enum>()
|
||||||
@ -129,7 +129,7 @@ so that we can do a sanity check on it.
|
|||||||
{
|
{
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
|
|
||||||
offset += std::sprintf(buffer, <em>"ENUM(%s, int", Enum::_name()</em>);
|
offset += std::sprintf(buffer, <em>"BETTER_ENUM(%s, int", Enum::_name()</em>);
|
||||||
|
|
||||||
<em>for</em> (<em>Enum value</em> : <em>Enum::_values()</em>) {
|
<em>for</em> (<em>Enum value</em> : <em>Enum::_values()</em>) {
|
||||||
offset +=
|
offset +=
|
||||||
@ -166,8 +166,10 @@ Now, we can write and run this code.
|
|||||||
It prints:
|
It prints:
|
||||||
|
|
||||||
~~~comment
|
~~~comment
|
||||||
ENUM(Channel, int, Red = 0, Green = 1, Blue = 2)
|
BETTER_ENUM(Channel, int, Red = 0, Green = 1, Blue = 2)
|
||||||
ENUM(Depth, int, TrueColor = 1, HighColor = 0)
|
BETTER_ENUM(Depth, int, TrueColor = 1, HighColor = 0)
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
%% description = Contrived example that shows static memory allocation.
|
%% 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.
|
||||||
173
doc/demo/105-c++17-reflection.md
Normal file
173
doc/demo/105-c++17-reflection.md
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
## 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,6 +7,8 @@ import string
|
|||||||
import transform
|
import transform
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
|
import sys
|
||||||
|
import urllib
|
||||||
|
|
||||||
TEMPLATE_DIRECTORY = "template"
|
TEMPLATE_DIRECTORY = "template"
|
||||||
OUTPUT_DIRECTORY = "html"
|
OUTPUT_DIRECTORY = "html"
|
||||||
@ -83,15 +85,24 @@ def compose_page(relative_path, definitions):
|
|||||||
definitions["canonical"] = canonical
|
definitions["canonical"] = canonical
|
||||||
definitions["prefix"] = prefix
|
definitions["prefix"] = prefix
|
||||||
|
|
||||||
|
definitions["quoted_url"] = urllib.quote(definitions["canonical"], "")
|
||||||
|
definitions["quoted_title"] = urllib.quote(definitions["title"], "")
|
||||||
|
|
||||||
if "class" not in definitions:
|
if "class" not in definitions:
|
||||||
definitions["class"] = ""
|
definitions["class"] = ""
|
||||||
|
|
||||||
text = templates["page"]
|
text = templates["page"]
|
||||||
text = scrub_comments(text)
|
|
||||||
|
|
||||||
while '$' in text:
|
while True:
|
||||||
text = apply_template(text, definitions)
|
new_text = scrub_comments(text)
|
||||||
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
|
||||||
|
|
||||||
text = "<!-- Generated automatically - edit the templates! -->\n\n" + text
|
text = "<!-- Generated automatically - edit the templates! -->\n\n" + text
|
||||||
|
|
||||||
@ -129,7 +140,9 @@ def compose_general_page(relative_path):
|
|||||||
write_page(relative_path, text)
|
write_page(relative_path, text)
|
||||||
|
|
||||||
def list_general_pages():
|
def list_general_pages():
|
||||||
return glob.glob("*.md")
|
return filter(
|
||||||
|
lambda s: not os.path.splitext(os.path.basename(s))[0].isupper(),
|
||||||
|
glob.glob("*.md"))
|
||||||
|
|
||||||
def process_threaded(directory):
|
def process_threaded(directory):
|
||||||
sources = glob.glob(os.path.join(directory, "*.md"))
|
sources = glob.glob(os.path.join(directory, "*.md"))
|
||||||
@ -143,7 +156,7 @@ def process_threaded(directory):
|
|||||||
|
|
||||||
source_file = \
|
source_file = \
|
||||||
os.path.splitext(os.path.basename(file))[0] + "." + CXX_EXTENSION
|
os.path.splitext(os.path.basename(file))[0] + "." + CXX_EXTENSION
|
||||||
source_link = "$repo/blob/$version/example/" + source_file
|
source_link = "$repo/blob/$ref/example/" + source_file
|
||||||
|
|
||||||
definitions[directory + "_body"] = definitions["body"]
|
definitions[directory + "_body"] = definitions["body"]
|
||||||
definitions["body"] = templates[directory]
|
definitions["body"] = templates[directory]
|
||||||
@ -183,6 +196,10 @@ def generate_sitemap():
|
|||||||
for url in generated:
|
for url in generated:
|
||||||
text += " <url>\n"
|
text += " <url>\n"
|
||||||
text += " <loc>%s</loc>\n" % url
|
text += " <loc>%s</loc>\n" % url
|
||||||
|
|
||||||
|
if ".html" not in url:
|
||||||
|
text += " <priority>1.0</priority>\n"
|
||||||
|
|
||||||
text += " </url>\n"
|
text += " </url>\n"
|
||||||
|
|
||||||
text += "</urlset>\n"
|
text += "</urlset>\n"
|
||||||
@ -192,6 +209,9 @@ def generate_sitemap():
|
|||||||
def main():
|
def main():
|
||||||
load_templates()
|
load_templates()
|
||||||
|
|
||||||
|
if not (len(sys.argv) >= 2 and sys.argv[1] == "--web"):
|
||||||
|
templates["ga"] = ""
|
||||||
|
|
||||||
remove_output_directory()
|
remove_output_directory()
|
||||||
|
|
||||||
process_threaded(TUTORIAL_DIRECTORY)
|
process_threaded(TUTORIAL_DIRECTORY)
|
||||||
|
|||||||
BIN
doc/image/sample.gif
Normal file
BIN
doc/image/sample.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 79 KiB |
190
doc/index.md
190
doc/index.md
@ -1,9 +1,3 @@
|
|||||||
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">
|
<div class="splash">
|
||||||
<pre class="left">enable
|
<pre class="left">enable
|
||||||
|
|
||||||
@ -11,7 +5,7 @@ declare
|
|||||||
|
|
||||||
|
|
||||||
parse
|
parse
|
||||||
print
|
format
|
||||||
|
|
||||||
|
|
||||||
count
|
count
|
||||||
@ -19,6 +13,7 @@ iterate
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
switch
|
switch
|
||||||
|
|
||||||
|
|
||||||
@ -29,22 +24,25 @@ switch
|
|||||||
safe cast
|
safe cast
|
||||||
|
|
||||||
|
|
||||||
at compile time</pre>
|
during
|
||||||
<pre class="right"><em>#include</em> <<em>enum.h</em>>
|
compilation
|
||||||
|
</pre>
|
||||||
|
<pre class="right"><em>#include <enum.h></em>
|
||||||
|
|
||||||
<em>ENUM</em>(<em>Channel</em>, <em>int</em>, <em>Red</em> = <em>1</em>, <em>Green</em>, <em>Blue</em>)
|
<em>BETTER_ENUM(Channel, int, Red = 1, Green, Blue)</em>
|
||||||
|
|
||||||
|
|
||||||
Channel c = <em>Channel::_from_string("Red")</em>;
|
Channel c = <em>Channel::_from_string("Red")</em>;
|
||||||
const char *s = <em>c._to_string()</em>;
|
const char *s = <em>c._to_string()</em>;
|
||||||
|
|
||||||
|
|
||||||
size_t n = <em>Channel::_size</em>;
|
size_t n = <em>Channel::_size()</em>;
|
||||||
<em>for</em> (<em>Channel c</em> : <em>Channel::_values()</em>)
|
<em>for (Channel c : Channel::_values())</em> {
|
||||||
run_some_function(<em>c</em>);
|
run_some_function(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
<em>switch</em> (<em>c</em>) {
|
<em>switch (c)</em> {
|
||||||
<em>case Channel::Red</em>: // ...
|
<em>case Channel::Red</em>: // ...
|
||||||
<em>case Channel::Green</em>: // ...
|
<em>case Channel::Green</em>: // ...
|
||||||
<em>case Channel::Blue</em>: // ...
|
<em>case Channel::Blue</em>: // ...
|
||||||
@ -54,32 +52,57 @@ size_t n = <em>Channel::_size</em>;
|
|||||||
Channel c = <em>Channel::_from_integral(3)</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>
|
</div>
|
||||||
|
|
||||||
### What do you get?
|
<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
|
||||||
|
|
||||||
<ul class="blurbs">
|
<ul class="blurbs">
|
||||||
<li class="even">
|
<li class="zero-mod-two zero-mod-three">
|
||||||
<strong>Uniform interface for $cxx98 and $cxx11</strong>
|
<strong>Unobtrusive syntax</strong>
|
||||||
<em>Scoped, sized, reflective enums for $cxx98.</em>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<strong>Compile-time reflection</strong>
|
|
||||||
<em>
|
<em>
|
||||||
Have the compiler do additional enum processing using your own
|
No ugly macros. Use initializers as with built-in <code>enums</code>.
|
||||||
templates or <code>constexpr</code> functions.
|
Internal members have underscores to avoid clashing with your constant
|
||||||
|
names.
|
||||||
</em>
|
</em>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="even">
|
<li class="one-mod-two one-mod-three">
|
||||||
<strong>Non-contiguous sequences</strong>
|
<strong>No external dependencies</strong>
|
||||||
<em>
|
<em>
|
||||||
Iteration and count much easier to maintain than with an extra "count"
|
Uses only standard $cxx. Installation is simple — just download
|
||||||
constant and making assumptions.
|
<code>enum.h</code>. There are no objects or libraries to link with.
|
||||||
</em>
|
</em>
|
||||||
</li>
|
</li>
|
||||||
<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>
|
<strong>Plays nice with <code>switch</code></strong>
|
||||||
<em>
|
<em>
|
||||||
Use a Better Enum like a built-in <code>enum</code>, and still have the
|
Use a Better Enum like a built-in <code>enum</code>, and still have the
|
||||||
@ -87,15 +110,7 @@ Channel c = <em>Channel::_from_integral(3)</em>;
|
|||||||
</em>
|
</em>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="even">
|
<li class="zero-mod-two one-mod-three">
|
||||||
<strong>Unobtrusive syntax</strong>
|
|
||||||
<em>
|
|
||||||
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>
|
<strong>Don't repeat yourself</strong>
|
||||||
<em>
|
<em>
|
||||||
No more unmaintanable maps or <code>switch</code> statements for
|
No more unmaintanable maps or <code>switch</code> statements for
|
||||||
@ -103,29 +118,48 @@ Channel c = <em>Channel::_from_integral(3)</em>;
|
|||||||
</em>
|
</em>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="even">
|
<li class="one-mod-two two-mod-three">
|
||||||
<strong>No build-time generator needed</strong>
|
<strong>Non-contiguous sequences</strong>
|
||||||
<em>
|
<em>
|
||||||
Just include <code>enum.h</code>. It's a metaprogram executed by your
|
Iteration and counting are much easier to maintain than with an extra
|
||||||
compiler.
|
<code>Count</code> constant and assuming a dense range.
|
||||||
</em>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<strong>Fast compilation</strong>
|
|
||||||
<em>
|
|
||||||
Much less impact on build time than even just including
|
|
||||||
<code>iostream</code>.
|
|
||||||
</em>
|
</em>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="even">
|
<li class="zero-mod-two zero-mod-three">
|
||||||
<strong>No external dependencies</strong>
|
<strong>Fast compilation</strong>
|
||||||
<em>
|
<em>
|
||||||
Uses standard $cxx and supported on major compilers. Installation is
|
Much less impact on build time than even just including
|
||||||
simple — just download <code>enum.h</code>.
|
<code>iostream</code>. <code>enum.h</code> is only slightly more than 1000
|
||||||
|
lines long.
|
||||||
</em>
|
</em>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
|
||||||
|
<li class="one-mod-two one-mod-three">
|
||||||
|
<strong>Compile-time reflection</strong>
|
||||||
|
<em>
|
||||||
|
Have the compiler do additional enum processing using your own
|
||||||
|
templates or <code>constexpr</code> functions.
|
||||||
|
</em>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="zero-mod-two two-mod-three">
|
||||||
|
<strong>Uniform interface for $cxx98, $cxx11</strong>
|
||||||
|
<em>
|
||||||
|
Scoped, sized, reflective enums for $cxx98, and an easy upgrade
|
||||||
|
path.
|
||||||
|
</em>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="one-mod-two zero-mod-three">
|
||||||
|
<strong>Stream operators</strong>
|
||||||
|
<em>
|
||||||
|
Write enum names directly to <code>std::cout</code> or use
|
||||||
|
<code>boost::lexical_cast</code>.
|
||||||
|
</em>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="zero-mod-two one-mod-three">
|
||||||
<strong>Free and open source</strong>
|
<strong>Free and open source</strong>
|
||||||
<em>
|
<em>
|
||||||
Released under the BSD license for use in any project, free or commercial.
|
Released under the BSD license for use in any project, free or commercial.
|
||||||
@ -135,40 +169,18 @@ Channel c = <em>Channel::_from_integral(3)</em>;
|
|||||||
|
|
||||||
<div class="hack"></div>
|
<div class="hack"></div>
|
||||||
|
|
||||||
### It's what built-in enums ought to do.
|
### Documentation
|
||||||
|
|
||||||
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">
|
<ul class="blurbs resources">
|
||||||
<li class="even">
|
<li class="zero-mod-two zero-mod-three">
|
||||||
<a id="Tutorial"></a>
|
<a id="Tutorial"></a>
|
||||||
<strong>Tutorial</strong>
|
<strong>Tutorial</strong>
|
||||||
<ol>
|
<ol>
|
||||||
$tutorial_toc
|
$tutorial_toc
|
||||||
</ol>
|
</ol>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
|
||||||
|
<li class="one-mod-two one-mod-three">
|
||||||
<strong>Reference</strong>
|
<strong>Reference</strong>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="${prefix}ApiReference.html">API reference</a></li>
|
<li><a href="${prefix}ApiReference.html">API reference</a></li>
|
||||||
@ -176,12 +188,20 @@ The library notionally <em>extends</em> $cxx, adding oft-needed features.
|
|||||||
<li><a href="${prefix}OptInFeatures.html">Opt-in features</a></li>
|
<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}ExtendingLimits.html">Extending limits</a></li>
|
||||||
<li><a href="${prefix}Performance.html">Performance</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>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="even">
|
<li class="zero-mod-two two-mod-three">
|
||||||
<a id="CompileTimeDemos"></a>
|
<a id="CompileTimeDemos"></a>
|
||||||
<strong>Compile-time demos</strong>
|
<strong>Advanced</strong>
|
||||||
<ul>
|
<ul>
|
||||||
$demo_toc
|
$demo_toc
|
||||||
</ul>
|
</ul>
|
||||||
@ -192,8 +212,8 @@ The library notionally <em>extends</em> $cxx, adding oft-needed features.
|
|||||||
|
|
||||||
%% title = Clean reflective enums for C++
|
%% title = Clean reflective enums for C++
|
||||||
|
|
||||||
%% description = Reflective enums for C++ with clean syntax, in a header-only
|
%% description = Reflective enums in a single header file, with clean syntax.
|
||||||
library. Can be converted to strings, iterated, counted, and used for
|
The enums can be converted to string, iterated, and counted, at run time or
|
||||||
metaprogramming. Free under the BSD license.
|
as part of metaprogramming. Free and open source under the BSD license.
|
||||||
|
|
||||||
%% class = index
|
%% class = index
|
||||||
|
|||||||
1102
doc/mistune.py
Executable file
1102
doc/mistune.py
Executable file
File diff suppressed because it is too large
Load Diff
@ -1,10 +0,0 @@
|
|||||||
<?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
Normal file
1
doc/template/cxx14.tmpl
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
<span class="cpp">C++</span><span class="eleven">14</span>
|
||||||
1
doc/template/cxx17.tmpl
vendored
Normal file
1
doc/template/cxx17.tmpl
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
<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>
|
<p>
|
||||||
This page is an advanced demo showing the kind of compile-time code you can
|
This is an example of code you can write on top of Better Enums. It's a valid
|
||||||
write on top of Better Enums. You can <a href="$source">download</a> it and
|
program — you can <a href="$source">download</a> it and try it out. The
|
||||||
try it out.
|
program is also part of the test suite.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
$demo_body
|
$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/$version/enum.h"
|
href="https://raw.githubusercontent.com/aantron/better-enums/$ref/enum.h"
|
||||||
download
|
download
|
||||||
5
doc/template/footer.tmpl
vendored
5
doc/template/footer.tmpl
vendored
@ -3,8 +3,9 @@
|
|||||||
|
|
||||||
<footer>
|
<footer>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
Copyright © 2015 Anton Bachin. Released under the BSD 2-clause license.
|
Copyright © 2015-2024 Anton Bachin. Released under the BSD 2-clause
|
||||||
See <a href="https://github.com/aantron/better-enums/blob/master/LICENSE">
|
license. See
|
||||||
|
<a href="https://github.com/aantron/better-enums/blob/$ref/doc/LICENSE">
|
||||||
LICENSE</a>.
|
LICENSE</a>.
|
||||||
<br />
|
<br />
|
||||||
This page is part of the documentation for Better Enums $version.
|
This page is part of the documentation for Better Enums $version.
|
||||||
|
|||||||
10
doc/template/ga.tmpl
vendored
Normal file
10
doc/template/ga.tmpl
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<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
Normal file
1
doc/template/ghfork.tmpl
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
<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
Normal file
1
doc/template/ghstar.tmpl
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
<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
Normal file
1
doc/template/ghwatch.tmpl
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
<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,6 +13,8 @@
|
|||||||
|
|
||||||
<link rel="stylesheet" href="${prefix}better-enums.css" />
|
<link rel="stylesheet" href="${prefix}better-enums.css" />
|
||||||
|
|
||||||
|
$ga
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body class="$class">
|
<body class="$class">
|
||||||
|
|
||||||
@ -23,7 +25,6 @@
|
|||||||
<a href="${prefix}index.html">Home</a>
|
<a href="${prefix}index.html">Home</a>
|
||||||
<a href="${prefix}tutorial/HelloWorld.html">Tutorial</a>
|
<a href="${prefix}tutorial/HelloWorld.html">Tutorial</a>
|
||||||
<a href="${prefix}ApiReference.html">Reference</a>
|
<a href="${prefix}ApiReference.html">Reference</a>
|
||||||
<a href="${prefix}Contact.html">Contact</a>
|
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
@ -31,11 +32,24 @@
|
|||||||
|
|
||||||
<header>
|
<header>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="back">{}</div>
|
<section>
|
||||||
|
|
||||||
<h1><a href="${prefix}index.html">Better Enums</a></h1>
|
<h1><a href="${prefix}index.html">Better Enums</a></h1>
|
||||||
<h2>Reflective compile-time enums for $cxx</h2>
|
<h2>Reflective compile-time enums for $cxx</h2>
|
||||||
<h3>Open-source under the BSD license</h3>
|
<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>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|||||||
1
doc/template/ref.tmpl
vendored
Normal file
1
doc/template/ref.tmpl
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
0.11.3
|
||||||
3
doc/template/tutorial.tmpl
vendored
3
doc/template/tutorial.tmpl
vendored
@ -1,6 +1,7 @@
|
|||||||
<p>
|
<p>
|
||||||
Welcome to the Better Enums tutorials! The code in this tutorial forms a
|
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.
|
valid program, which you can <a href="$source">download</a> and play with. The
|
||||||
|
program runs as part of the automated test suite.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
$tutorial_body
|
$tutorial_body
|
||||||
|
|||||||
2
doc/template/version.tmpl
vendored
2
doc/template/version.tmpl
vendored
@ -1 +1 @@
|
|||||||
0.9.0
|
0.11.3
|
||||||
@ -50,7 +50,7 @@ def camel_case(text):
|
|||||||
components = re.split("[ -]+", text)
|
components = re.split("[ -]+", text)
|
||||||
components = map(lambda s: s.capitalize(), components)
|
components = map(lambda s: s.capitalize(), components)
|
||||||
result = "".join(components)
|
result = "".join(components)
|
||||||
result = filter(lambda c: c not in ",!:-$()", result)
|
result = filter(lambda c: c not in ",!:-$()?", result)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
class HtmlRenderer(mistune.Renderer):
|
class HtmlRenderer(mistune.Renderer):
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
## Hello, World!
|
## Hello, World!
|
||||||
|
|
||||||
Download <a $download><code>enum.h</code></a>, then build this program with it:
|
Download <a $download><code>enum.h</code></a>, then compile this program:
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
<em>#include "enum.h"</em>
|
<em>#include "enum.h"</em>
|
||||||
|
|
||||||
<em>ENUM</em>(<em>Word</em>, <em>int</em>, <em>Hello</em>, <em>World</em>)
|
<em>BETTER_ENUM</em>(<em>Word</em>, <em>int</em>, <em>Hello</em>, <em>World</em>)
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
@ -20,4 +20,5 @@ Run it, and you should see the output "Hello, World!"
|
|||||||
|
|
||||||
Congratulations, you have just created your first Better Enum!
|
Congratulations, you have just created your first Better Enum!
|
||||||
|
|
||||||
%% description = Introductory Better Enums tutorial.
|
%% description = Introductory Better Enums tutorial - a simple, but complete,
|
||||||
|
Hello World program.
|
||||||
|
|||||||
@ -7,7 +7,7 @@ Let's begin by including `enum.h` and declaring our enum:
|
|||||||
|
|
||||||
<em>#include <enum.h></em>
|
<em>#include <enum.h></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>)
|
<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>)
|
||||||
|
|
||||||
We now have an `int`-sized enum with four constants.
|
We now have an `int`-sized enum with four constants.
|
||||||
|
|
||||||
@ -149,4 +149,6 @@ reference has a
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
%% description = Walkthrough of Better Enums conversion functions.
|
%% 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.
|
||||||
|
|||||||
@ -6,12 +6,12 @@ example, this:
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <enum.h>
|
#include <enum.h>
|
||||||
|
|
||||||
<em>ENUM(Channel, int, Red, Green = 2, Blue)</em>
|
<em>BETTER_ENUM(Channel, int, Red, Green = 2, Blue)</em>
|
||||||
|
|
||||||
int main()
|
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>;
|
Channel channel = <em>Channel::_values()[index]</em>;
|
||||||
std::cout << channel._to_integral() << " ";
|
std::cout << channel._to_integral() << " ";
|
||||||
}
|
}
|
||||||
@ -19,7 +19,7 @@ example, this:
|
|||||||
|
|
||||||
will print "0 2 3". And 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>;
|
const char *name = <em>Channel::_names()[index]</em>;
|
||||||
std::cout << name << " ";
|
std::cout << name << " ";
|
||||||
}
|
}
|
||||||
@ -46,4 +46,5 @@ If you are using $cxx11, you can have much nicer syntax:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
%% description = Iterating over all Better Enums constants.
|
%% 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.
|
||||||
|
|||||||
@ -5,7 +5,7 @@ A Better Enum can be used directly in a `switch` statement:
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
<em>#include <enum.h></em>
|
<em>#include <enum.h></em>
|
||||||
|
|
||||||
<em>ENUM(Channel, int, Red, Green, Blue)</em>
|
<em>BETTER_ENUM(Channel, int, Red, Green, Blue)</em>
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
@ -21,10 +21,16 @@ 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
|
If you miss a case or add a redundant one, your compiler should be able to give
|
||||||
you a warning — try it!
|
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;
|
std::cout << n << std::endl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
%% description = Usage in switch statements.
|
%% 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.
|
||||||
|
|||||||
77
doc/tutorial/5-map.md
Normal file
77
doc/tutorial/5-map.md
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
## 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.
|
||||||
34
doc/tutorial/6-iostreams.md
Normal file
34
doc/tutorial/6-iostreams.md
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
## 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.
|
||||||
@ -3,6 +3,12 @@
|
|||||||
This tutorial shows some of the safety features of Better Enums: scope, how to
|
This tutorial shows some of the safety features of Better Enums: scope, how to
|
||||||
control conversions, and the lack of a default constructor.
|
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
|
$internal_toc
|
||||||
|
|
||||||
### Scope
|
### Scope
|
||||||
@ -12,7 +18,7 @@ You have probably noticed by now that Better Enums are scoped: when you declare
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
<em>#include <enum.h></em>
|
<em>#include <enum.h></em>
|
||||||
|
|
||||||
<em>ENUM</em>(<em>Channel</em>, <em>int</em>, <em>Red</em> = <em>1</em>, <em>Green</em>, <em>Blue</em>)
|
<em>BETTER_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
|
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
|
`Channel`, and `Red` is accessible as `Channel::Red`. This is no big deal in
|
||||||
@ -20,7 +26,7 @@ $cxx11, which has `enum class`. In $cxx98, however, this typically requires
|
|||||||
effort. Better Enums brings scope uniformly to both variants. So, despite the
|
effort. Better Enums brings scope uniformly to both variants. So, despite the
|
||||||
above declaration, you can safely declare
|
above declaration, you can safely declare
|
||||||
|
|
||||||
<em>ENUM</em>(<em>Node</em>, <em>char</em>, <em>Red</em>, <em>Black</em>)
|
<em>BETTER_ENUM</em>(<em>Node</em>, <em>char</em>, <em>Red</em>, <em>Black</em>)
|
||||||
|
|
||||||
and everything will work as expected.
|
and everything will work as expected.
|
||||||
|
|
||||||
@ -47,33 +53,27 @@ will not compile:
|
|||||||
The reason this is not enabled by default is explained in the reference page on
|
The reason this is not enabled by default is explained in the reference page on
|
||||||
[strict conversions](${prefix}OptInFeatures.html#StrictConversions).
|
[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
|
### Default constructor
|
||||||
|
|
||||||
Better Enums don't have a default constructor, for three reasons.
|
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
|
||||||
- Better Enums is a library that can't know what your application would like
|
you uncomment this code, the program won't compile:
|
||||||
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
|
~~~comment
|
||||||
Channel channel;
|
Channel channel;
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
This may be too strict, and I may relax it in the future. In the meantime, the
|
If this is too strict for your project, you can relax it as described
|
||||||
solution sketched in the [special values demo](${prefix}demo/SpecialValues.html)
|
[here](${prefix}OptInFeatures.html#DefaultConstructors).
|
||||||
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
%% description = Type safety features and limitations.
|
%% description = Better Enums type safety features and limitations.
|
||||||
@ -7,7 +7,7 @@ will declare a more unusual enum than the ones we have seen.
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
<em>#include <enum.h></em>
|
<em>#include <enum.h></em>
|
||||||
|
|
||||||
<em>ENUM</em>(<em>ContentType</em>, <em>short</em>,
|
<em>BETTER_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>)
|
<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
|
This is for a hypothetical multimedia container file format. Perhaps the files
|
||||||
@ -80,4 +80,5 @@ types containg enums. The enums will behave as expected.
|
|||||||
compatible with $cxx98, where those names aren't available in a portable
|
compatible with $cxx98, where those names aren't available in a portable
|
||||||
manner.
|
manner.
|
||||||
|
|
||||||
%% description = Underlying representation.
|
%% description = The underlying memory representation of a Better Enum,
|
||||||
|
including size and alignment.
|
||||||
@ -15,7 +15,7 @@ get an idea of what can be done. Here, you will see the basics.
|
|||||||
|
|
||||||
<em>#include <enum.h></em>
|
<em>#include <enum.h></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>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>constexpr</em> Channel channel = <em>Channel::_from_integral(2)</em>;
|
<em>constexpr</em> Channel channel = <em>Channel::_from_integral(2)</em>;
|
||||||
<em>constexpr</em> int value = <em>channel._to_integral()</em>;
|
<em>constexpr</em> int value = <em>channel._to_integral()</em>;
|
||||||
@ -48,4 +48,5 @@ You can also do things such as:
|
|||||||
Which prints "5", the length of "Green". That 5 was also computed during
|
Which prints "5", the length of "Green". That 5 was also computed during
|
||||||
compilation.
|
compilation.
|
||||||
|
|
||||||
%% description = Introduction to compile-time conversions.
|
%% description = Better Enums can be used entirely at compile time in C++11. All
|
||||||
|
conversion functions are available for constexpr functions or templates.
|
||||||
@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
// Hello, World!
|
// Hello, World!
|
||||||
//
|
//
|
||||||
// Download enum.h, then build this program with it:
|
// Download enum.h, then compile this program:
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "enum.h"
|
#include "enum.h"
|
||||||
|
|
||||||
ENUM(Word, int, Hello, World)
|
BETTER_ENUM(Word, int, Hello, World)
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -44,10 +44,10 @@ constexpr Enum invalid_impl<Enum>() { return Enum::Value; }
|
|||||||
|
|
||||||
// Now, we can declare enums like these:
|
// Now, we can declare enums like these:
|
||||||
|
|
||||||
ENUM(Channel, int, Red, Green, Blue, Invalid)
|
BETTER_ENUM(Channel, int, Red, Green, Blue, Invalid)
|
||||||
// Invalid is the invalid value by default
|
// Invalid is the invalid value by default
|
||||||
|
|
||||||
ENUM(Compression, int, Undefined, None, Huffman)
|
BETTER_ENUM(Compression, int, Undefined, None, Huffman)
|
||||||
OVERRIDE_INVALID(Compression, Undefined)
|
OVERRIDE_INVALID(Compression, Undefined)
|
||||||
|
|
||||||
// and use them:
|
// and use them:
|
||||||
@ -69,7 +69,7 @@ template <typename Enum>
|
|||||||
constexpr Enum default_impl()
|
constexpr Enum default_impl()
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
Enum::_size < 2 ?
|
Enum::_size() < 2 ?
|
||||||
throw std::logic_error("enum has no valid constants") :
|
throw std::logic_error("enum has no valid constants") :
|
||||||
Enum::_values()[0] == invalid_impl<Enum>() ?
|
Enum::_values()[0] == invalid_impl<Enum>() ?
|
||||||
Enum::_values()[1] :
|
Enum::_values()[1] :
|
||||||
@ -98,7 +98,7 @@ static_assert(default_impl<Compression>() == +Compression::None, "");
|
|||||||
|
|
||||||
// And, if you do
|
// And, if you do
|
||||||
|
|
||||||
ENUM(Answer, int, Yes, No, Invalid)
|
BETTER_ENUM(Answer, int, Yes, No, Invalid)
|
||||||
// OVERRIDE_DEFAULT(Answer, Invalid)
|
// OVERRIDE_DEFAULT(Answer, Invalid)
|
||||||
|
|
||||||
// you will get a helpful compile-time error saying Answer: default cannot equal
|
// 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)
|
constexpr Enum max_loop(Enum accumulator, size_t index)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
index >= Enum::_size ? accumulator :
|
index >= Enum::_size() ? accumulator :
|
||||||
Enum::_values()[index] > accumulator ?
|
Enum::_values()[index] > accumulator ?
|
||||||
max_loop<Enum>(Enum::_values()[index], index + 1) :
|
max_loop<Enum>(Enum::_values()[index], index + 1) :
|
||||||
max_loop<Enum>(accumulator, 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
|
// declared. We just declare enums, and the numeric values of their constants
|
||||||
// will be bit indices. The rest is straightforward.
|
// will be bit indices. The rest is straightforward.
|
||||||
|
|
||||||
ENUM(EFLAGS, int,
|
BETTER_ENUM(EFLAGS, int,
|
||||||
Carry, Parity = 2, Adjust = 4, Zero, Sign, Trap, Interrupt, Direction,
|
Carry, Parity = 2, Adjust = 4, Zero, Sign, Trap, Interrupt, Direction,
|
||||||
Overflow, NestedTask = 14, Resume = 16, V8086, AlignmentCheck,
|
Overflow, NestedTask = 14, Resume = 16, V8086, AlignmentCheck,
|
||||||
CPUIDPresent = 21)
|
CPUIDPresent = 21)
|
||||||
@ -10,7 +10,7 @@
|
|||||||
// Ok, so it's not really a quine, because we won't be writing all the code
|
// 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
|
// 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
|
// better ways to dump the definition than shown here. You could simply define a
|
||||||
// macro that expands to an ENUM declaration and also stringizes it.
|
// macro that expands to an BETTER_ENUM declaration and also stringizes it.
|
||||||
//
|
//
|
||||||
// But that's not the point here. The point of this page is to show some of the
|
// 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
|
// 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:
|
// Now, let's declare some enums to dump later:
|
||||||
|
|
||||||
ENUM(Channel, int, Red, Green, Blue)
|
BETTER_ENUM(Channel, int, Red, Green, Blue)
|
||||||
ENUM(Depth, int, TrueColor = 1, HighColor = 0)
|
BETTER_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)
|
constexpr size_t constants_length(size_t index = 0, size_t accumulator = 0)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
index >= Enum::_size ? accumulator :
|
index >= Enum::_size() ? accumulator :
|
||||||
constants_length<Enum>(
|
constants_length<Enum>(
|
||||||
index + 1, accumulator
|
index + 1, accumulator
|
||||||
+ string_length(", ")
|
+ string_length(", ")
|
||||||
@ -99,7 +99,7 @@ template <typename Enum>
|
|||||||
constexpr size_t declaration_length()
|
constexpr size_t declaration_length()
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
string_length("ENUM(")
|
string_length("BETTER_ENUM(")
|
||||||
+ string_length(Enum::_name())
|
+ string_length(Enum::_name())
|
||||||
+ string_length(", int")
|
+ string_length(", int")
|
||||||
+ constants_length<Enum>()
|
+ constants_length<Enum>()
|
||||||
@ -127,7 +127,7 @@ size_t format(char *buffer)
|
|||||||
{
|
{
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
|
|
||||||
offset += std::sprintf(buffer, "ENUM(%s, int", Enum::_name());
|
offset += std::sprintf(buffer, "BETTER_ENUM(%s, int", Enum::_name());
|
||||||
|
|
||||||
for (Enum value : Enum::_values()) {
|
for (Enum value : Enum::_values()) {
|
||||||
offset +=
|
offset +=
|
||||||
@ -163,5 +163,5 @@ int main()
|
|||||||
|
|
||||||
// It prints:
|
// It prints:
|
||||||
//
|
//
|
||||||
// ENUM(Channel, int, Red = 0, Green = 1, Blue = 2)
|
// BETTER_ENUM(Channel, int, Red = 0, Green = 1, Blue = 2)
|
||||||
// ENUM(Depth, int, TrueColor = 1, HighColor = 0)
|
// BETTER_ENUM(Depth, int, TrueColor = 1, HighColor = 0)
|
||||||
152
example/105-c++17-reflection.cc
Normal file
152
example/105-c++17-reflection.cc
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
// 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>
|
#include <enum.h>
|
||||||
|
|
||||||
ENUM(Channel, int, Cyan = 1, Magenta, Yellow, Black)
|
BETTER_ENUM(Channel, int, Cyan = 1, Magenta, Yellow, Black)
|
||||||
|
|
||||||
// We now have an int-sized enum with four constants.
|
// We now have an int-sized enum with four constants.
|
||||||
//
|
//
|
||||||
|
|||||||
@ -8,12 +8,12 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <enum.h>
|
#include <enum.h>
|
||||||
|
|
||||||
ENUM(Channel, int, Red, Green = 2, Blue)
|
BETTER_ENUM(Channel, int, Red, Green = 2, Blue)
|
||||||
|
|
||||||
int main()
|
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];
|
Channel channel = Channel::_values()[index];
|
||||||
std::cout << channel._to_integral() << " ";
|
std::cout << channel._to_integral() << " ";
|
||||||
}
|
}
|
||||||
@ -21,7 +21,7 @@ int main()
|
|||||||
|
|
||||||
// will print "0 2 3". And this:
|
// 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];
|
const char *name = Channel::_names()[index];
|
||||||
std::cout << name << " ";
|
std::cout << name << " ";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <enum.h>
|
#include <enum.h>
|
||||||
|
|
||||||
ENUM(Channel, int, Red, Green, Blue)
|
BETTER_ENUM(Channel, int, Red, Green, Blue)
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
@ -22,6 +22,8 @@ int main()
|
|||||||
|
|
||||||
// If you miss a case or add a redundant one, your compiler should be able to
|
// If you miss a case or add a redundant one, your compiler should be able to
|
||||||
// give you a warning - try it!
|
// give you a warning - try it!
|
||||||
|
//
|
||||||
|
// Note that on msvc, you may need to enable warning C4062.
|
||||||
|
|
||||||
|
|
||||||
std::cout << n << std::endl;
|
std::cout << n << std::endl;
|
||||||
|
|||||||
74
example/5-map.cc
Normal file
74
example/5-map.cc
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
// 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.
|
||||||
30
example/6-iostreams.cc
Normal file
30
example/6-iostreams.cc
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// 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.
|
||||||
@ -5,6 +5,12 @@
|
|||||||
// This tutorial shows some of the safety features of Better Enums: scope, how
|
// This tutorial shows some of the safety features of Better Enums: scope, how
|
||||||
// to control conversions, and the lack of a default constructor.
|
// 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
|
// Scope
|
||||||
//
|
//
|
||||||
// You have probably noticed by now that Better Enums are scoped: when you
|
// You have probably noticed by now that Better Enums are scoped: when you
|
||||||
@ -13,7 +19,7 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <enum.h>
|
#include <enum.h>
|
||||||
|
|
||||||
ENUM(Channel, int, Red = 1, Green, Blue)
|
BETTER_ENUM(Channel, int, Red = 1, Green, Blue)
|
||||||
|
|
||||||
// you don't get names such as Red in the global namespace. Instead, you get
|
// 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,
|
// Channel, and Red is accessible as Channel::Red. This is no big deal in C++11,
|
||||||
@ -21,7 +27,7 @@ ENUM(Channel, int, Red = 1, Green, Blue)
|
|||||||
// Better Enums brings scope uniformly to both variants. So, despite the above
|
// Better Enums brings scope uniformly to both variants. So, despite the above
|
||||||
// declaration, you can safely declare
|
// declaration, you can safely declare
|
||||||
|
|
||||||
ENUM(Node, char, Red, Black)
|
BETTER_ENUM(Node, char, Red, Black)
|
||||||
|
|
||||||
// and everything will work as expected.
|
// and everything will work as expected.
|
||||||
|
|
||||||
@ -45,28 +51,20 @@ int main()
|
|||||||
// The reason this is not enabled by default is explained in the reference page
|
// The reason this is not enabled by default is explained in the reference page
|
||||||
// on strict conversions.
|
// 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
|
// Default constructor
|
||||||
//
|
//
|
||||||
// Better Enums don't have a default constructor, for three reasons.
|
// 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
|
||||||
// 1. Better Enums is a library that can't know what your application would
|
// value. So, if you uncomment this code, the program won't compile:
|
||||||
// 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;
|
// Channel channel;
|
||||||
//
|
//
|
||||||
// This may be too strict, and I may relax it in the future. In the meantime,
|
// If this is too strict for your project, you can relax it as described here.
|
||||||
// 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;
|
return 0;
|
||||||
@ -9,7 +9,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <enum.h>
|
#include <enum.h>
|
||||||
|
|
||||||
ENUM(ContentType, short,
|
BETTER_ENUM(ContentType, short,
|
||||||
CompressedVideo = 5, PCM = 8, Subtitles = 17, Comment = 44)
|
CompressedVideo = 5, PCM = 8, Subtitles = 17, Comment = 44)
|
||||||
|
|
||||||
// This is for a hypothetical multimedia container file format. Perhaps the
|
// This is for a hypothetical multimedia container file format. Perhaps the
|
||||||
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
#include <enum.h>
|
#include <enum.h>
|
||||||
|
|
||||||
ENUM(Channel, int, Red = 1, Green = 2, Blue = 3)
|
BETTER_ENUM(Channel, int, Red = 1, Green = 2, Blue = 3)
|
||||||
|
|
||||||
constexpr Channel channel = Channel::_from_integral(2);
|
constexpr Channel channel = Channel::_from_integral(2);
|
||||||
constexpr int value = channel._to_integral();
|
constexpr int value = channel._to_integral();
|
||||||
@ -3,7 +3,7 @@ CXX := c++
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
ifndef CXXFLAGS
|
ifndef CXXFLAGS
|
||||||
CXXFLAGS := -std=c++11 -Wall -I .. -o
|
CXXFLAGS := -std=c++11 -Wall -I .. -I../extra -o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
SOURCES := $(wildcard *.cc)
|
SOURCES := $(wildcard *.cc)
|
||||||
|
|||||||
52
extra/better-enums/n4428.h
Normal file
52
extra/better-enums/n4428.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
// 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,18 +3,19 @@
|
|||||||
# This file is part of Better Enums, released under the BSD 2-clause license.
|
# 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.
|
# See LICENSE for details, or visit http://github.com/aantron/better-enums.
|
||||||
|
|
||||||
# This script generates the macros _ENUM_PP_MAP and _ENUM_ITERATE, used
|
# You only need this script if you are developing enum.h, or run into a limit.
|
||||||
# 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.
|
|
||||||
#
|
#
|
||||||
# _ENUM_PP_MAP has a limit, which determines the maximum number of constants an
|
# This script generates the macros BETTER_ENUMS_PP_MAP and BETTER_ENUMS_ITERATE,
|
||||||
# enum can have. By default, this limit is 64 constants.
|
# used internally by enum.h. These are already inlined into enum.h.
|
||||||
#
|
#
|
||||||
# _ENUM_ITERATE also has a limit. This one determines the maximum length of the
|
# BETTER_ENUMS_PP_MAP has a limit, which determines the maximum number of
|
||||||
# name of a constant that is followed by an initializer (" = 2") when compiling
|
# constants an enum can have. By default, this limit is 64 constants.
|
||||||
# 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
|
# BETTER_ENUMS_ITERATE also has a limit. This one determines the maximum length
|
||||||
# terminator).
|
# 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
|
# 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
|
# without changing enum.h. You need to generate an external macro file with
|
||||||
@ -28,7 +29,7 @@
|
|||||||
# 2. Build your code with an additional compiler flag:
|
# 2. Build your code with an additional compiler flag:
|
||||||
# - for gcc and clang, -DBETTER_ENUMS_MACRO_FILE='<MACRO_FILE>'
|
# - for gcc and clang, -DBETTER_ENUMS_MACRO_FILE='<MACRO_FILE>'
|
||||||
# - for VC++, /DBETTER_ENUMS_MACRO_FILE='<MACRO_FILE>'
|
# - for VC++, /DBETTER_ENUMS_MACRO_FILE='<MACRO_FILE>'
|
||||||
# or use any other method of getting these macros declared.
|
# or use any other method of getting these macros defined.
|
||||||
# 3. Compile your code. Your macro file should be included, and enum.h should
|
# 3. Compile your code. Your macro file should be included, and enum.h should
|
||||||
# happily work with whatever limits you chose.
|
# happily work with whatever limits you chose.
|
||||||
|
|
||||||
@ -66,35 +67,38 @@ def generate(stream, constants, length, script):
|
|||||||
print >> stream, ''
|
print >> stream, ''
|
||||||
print >> stream, '#pragma once'
|
print >> stream, '#pragma once'
|
||||||
print >> stream, ''
|
print >> stream, ''
|
||||||
print >> stream, '#ifndef _BETTER_ENUM_MACRO_FILE_H_'
|
print >> stream, '#ifndef BETTER_ENUMS_MACRO_FILE_H'
|
||||||
print >> stream, '#define _BETTER_ENUM_MACRO_FILE_H_'
|
print >> stream, '#define BETTER_ENUMS_MACRO_FILE_H'
|
||||||
|
|
||||||
print >> stream, ''
|
print >> stream, ''
|
||||||
print >> stream, '#define _ENUM_PP_MAP(macro, data, ...) \\'
|
print >> stream, '#define BETTER_ENUMS_PP_MAP(macro, data, ...) \\'
|
||||||
print >> stream, ' _ENUM_ID(_ENUM_A(_ENUM_PP_MAP_VAR_COUNT, ' + \
|
print >> stream, ' BETTER_ENUMS_ID( \\'
|
||||||
'_ENUM_PP_COUNT(__VA_ARGS__)) \\'
|
print >> stream, ' BETTER_ENUMS_APPLY( \\'
|
||||||
|
print >> stream, ' BETTER_ENUMS_PP_MAP_VAR_COUNT, \\'
|
||||||
|
print >> stream, ' BETTER_ENUMS_PP_COUNT(__VA_ARGS__)) \\'
|
||||||
print >> stream, ' (macro, data, __VA_ARGS__))'
|
print >> stream, ' (macro, data, __VA_ARGS__))'
|
||||||
|
|
||||||
print >> stream, ''
|
print >> stream, ''
|
||||||
print >> stream, '#define _ENUM_PP_MAP_VAR_COUNT(count) ' + \
|
print >> stream, '#define BETTER_ENUMS_PP_MAP_VAR_COUNT(count) ' + \
|
||||||
'_ENUM_M ## count'
|
'BETTER_ENUMS_M ## count'
|
||||||
|
|
||||||
print >> stream, ''
|
print >> stream, ''
|
||||||
print >> stream, '#define _ENUM_A(macro, ...) _ENUM_ID(macro(__VA_ARGS__))'
|
print >> stream, '#define BETTER_ENUMS_APPLY(macro, ...) ' + \
|
||||||
|
'BETTER_ENUMS_ID(macro(__VA_ARGS__))'
|
||||||
|
|
||||||
print >> stream, ''
|
print >> stream, ''
|
||||||
print >> stream, '#define _ENUM_ID(x) x'
|
print >> stream, '#define BETTER_ENUMS_ID(x) x'
|
||||||
|
|
||||||
print >> stream, ''
|
print >> stream, ''
|
||||||
print >> stream, '#define _ENUM_M1(m, d, x) m(d,0,x)'
|
print >> stream, '#define BETTER_ENUMS_M1(m, d, x) m(d,0,x)'
|
||||||
for index in range(2, constants + 1):
|
for index in range(2, constants + 1):
|
||||||
print >> stream, '#define _ENUM_M' + str(index) + \
|
print >> stream, '#define BETTER_ENUMS_M' + str(index) + \
|
||||||
'(m,d,x,...) m(d,' + str(index - 1) + \
|
'(m,d,x,...) m(d,' + str(index - 1) + ',x) \\'
|
||||||
',x) _ENUM_ID(_ENUM_M' + str(index - 1) + \
|
print >> stream, ' BETTER_ENUMS_ID(BETTER_ENUMS_M' + \
|
||||||
'(m,d,__VA_ARGS__))'
|
str(index - 1) + '(m,d,__VA_ARGS__))'
|
||||||
|
|
||||||
print >> stream, ''
|
print >> stream, ''
|
||||||
pp_count_impl_prefix = '#define _ENUM_PP_COUNT_IMPL(_1,'
|
pp_count_impl_prefix = '#define BETTER_ENUMS_PP_COUNT_IMPL(_1,'
|
||||||
stream.write(pp_count_impl_prefix)
|
stream.write(pp_count_impl_prefix)
|
||||||
pp_count_impl = MultiLine(stream = stream, indent = 4,
|
pp_count_impl = MultiLine(stream = stream, indent = 4,
|
||||||
initial_column = len(pp_count_impl_prefix))
|
initial_column = len(pp_count_impl_prefix))
|
||||||
@ -106,10 +110,11 @@ def generate(stream, constants, length, script):
|
|||||||
print >> stream, ''
|
print >> stream, ''
|
||||||
|
|
||||||
print >> stream, ''
|
print >> stream, ''
|
||||||
|
print >> stream, '#define BETTER_ENUMS_PP_COUNT(...) \\'
|
||||||
pp_count_prefix = \
|
pp_count_prefix = \
|
||||||
'#define _ENUM_PP_COUNT(...) _ENUM_ID(_ENUM_PP_COUNT_IMPL(__VA_ARGS__,'
|
' BETTER_ENUMS_ID(BETTER_ENUMS_PP_COUNT_IMPL(__VA_ARGS__,'
|
||||||
stream.write(pp_count_prefix)
|
stream.write(pp_count_prefix)
|
||||||
pp_count = MultiLine(stream = stream, indent = 4,
|
pp_count = MultiLine(stream = stream, indent = 8,
|
||||||
initial_column = len(pp_count_prefix))
|
initial_column = len(pp_count_prefix))
|
||||||
for index in range(0, constants - 1):
|
for index in range(0, constants - 1):
|
||||||
pp_count.write(' ' + str(constants - index) + ',')
|
pp_count.write(' ' + str(constants - index) + ',')
|
||||||
@ -117,7 +122,7 @@ def generate(stream, constants, length, script):
|
|||||||
print >> stream, ''
|
print >> stream, ''
|
||||||
|
|
||||||
print >> stream, ''
|
print >> stream, ''
|
||||||
iterate_prefix = '#define _ENUM_ITERATE(X, f, l)'
|
iterate_prefix = '#define BETTER_ENUMS_ITERATE(X, f, l)'
|
||||||
stream.write(iterate_prefix)
|
stream.write(iterate_prefix)
|
||||||
iterate = MultiLine(stream = stream, indent = 4,
|
iterate = MultiLine(stream = stream, indent = 4,
|
||||||
initial_column = len(iterate_prefix))
|
initial_column = len(iterate_prefix))
|
||||||
@ -126,7 +131,7 @@ def generate(stream, constants, length, script):
|
|||||||
print >> stream, ''
|
print >> stream, ''
|
||||||
|
|
||||||
print >> stream, ''
|
print >> stream, ''
|
||||||
print >> stream, '#endif // #ifndef _BETTER_ENUM_MACRO_FILE_H_'
|
print >> stream, '#endif // #ifndef BETTER_ENUMS_MACRO_FILE_H'
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
if len(sys.argv) != 3:
|
if len(sys.argv) != 3:
|
||||||
|
|||||||
203
test/CMakeLists.txt
Normal file
203
test/CMakeLists.txt
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
# 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()
|
||||||
170
test/Makefile
170
test/Makefile
@ -1,13 +1,167 @@
|
|||||||
.PHONY : default
|
# Run "make" for quick builds while developing.
|
||||||
default :
|
# Run "make default-all" before submitting a pull request.
|
||||||
make -C ../doc examples
|
# Run "make clean" to clean up.
|
||||||
python test.py
|
# See doc/CONTRIBUTING.md for full instructions.
|
||||||
|
|
||||||
.PHONY : platform
|
CXXTEST_GENERATED := cxxtest/tests.cc
|
||||||
platform :
|
|
||||||
|
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 :
|
||||||
make -C ../doc examples
|
make -C ../doc examples
|
||||||
python test.py --all
|
|
||||||
|
# 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 : clean
|
.PHONY : clean
|
||||||
clean :
|
clean :
|
||||||
rm -rf platform *.obj
|
rm -rf build $(CXXTEST_GENERATED)
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
#include <iosfwd>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <cxxtest/TestSuite.h>
|
#include <cxxtest/TestSuite.h>
|
||||||
#include <enum.h>
|
#include <enum.h>
|
||||||
@ -12,17 +13,28 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
ENUM(Channel, short, Red, Green, Blue)
|
BETTER_ENUM(Channel, short, Red, Green, Blue)
|
||||||
ENUM(Depth, short, HighColor = 40, TrueColor = 20)
|
BETTER_ENUM(Depth, short, HighColor = 40, TrueColor = 20)
|
||||||
ENUM(Compression, short, None, Huffman, Default = Huffman)
|
BETTER_ENUM(Compression, short, None, Huffman, Default = Huffman)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Using _ENUM_HAVE_CONSTEXPR as a proxy for C++11 support. This should be
|
namespace test {
|
||||||
// changed to be more precise in the future.
|
|
||||||
#ifdef _ENUM_HAVE_CONSTEXPR
|
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)
|
||||||
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
// Type properties.
|
// Type properties.
|
||||||
static_assert_1(std::is_class<Channel>());
|
static_assert_1(std::is_class<Channel>());
|
||||||
@ -36,12 +48,14 @@ static_assert_1(std::is_integral<Channel::_integral>());
|
|||||||
static_assert_1(std::is_enum<Channel::_enumerated>());
|
static_assert_1(std::is_enum<Channel::_enumerated>());
|
||||||
|
|
||||||
static_assert_1((std::is_same<short, Channel::_integral>()));
|
static_assert_1((std::is_same<short, Channel::_integral>()));
|
||||||
static_assert_1((std::is_same<
|
// Temporarily disabled due to outdated libraries in Travis.
|
||||||
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>()));
|
static_assert_1(!(std::is_same<int, Channel::_integral>()));
|
||||||
static_assert_1(!(std::is_same<
|
// Temporarily disabled due to outdated libraries in Travis.
|
||||||
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(sizeof(Channel) == sizeof(short));
|
||||||
static_assert_1(alignof(Channel) == alignof(short));
|
static_assert_1(alignof(Channel) == alignof(short));
|
||||||
@ -52,13 +66,16 @@ static_assert_1((std::is_same<decltype(Channel::Red), Channel::_enumerated>()));
|
|||||||
|
|
||||||
// Supported constructors.
|
// Supported constructors.
|
||||||
|
|
||||||
#ifdef __clang__
|
// Apparently, this isn't supported by Clang in Travis.
|
||||||
static_assert_1(std::is_trivially_copyable<Channel>());
|
// #ifdef __clang__
|
||||||
#endif
|
// static_assert_1(std::is_trivially_copyable<Channel>());
|
||||||
|
// #endif
|
||||||
|
|
||||||
static_assert_1((std::is_constructible<Channel, Channel::_enumerated>()));
|
static_assert_1((std::is_constructible<Channel, Channel::_enumerated>()));
|
||||||
static_assert_1(!(std::is_constructible<Channel, Channel::_integral>()));
|
// "Passes" by causing a compilation error.
|
||||||
static_assert_1(!(std::is_constructible<Channel, Depth>()));
|
// 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>()));
|
||||||
|
|
||||||
// Commented out temporarily due to GCC 4.7- bug.
|
// Commented out temporarily due to GCC 4.7- bug.
|
||||||
// static_assert_1(!std::is_default_constructible<Channel>());
|
// static_assert_1(!std::is_default_constructible<Channel>());
|
||||||
@ -106,12 +123,23 @@ static_assert_1(
|
|||||||
static_assert_1(Channel::_is_valid("Green"));
|
static_assert_1(Channel::_is_valid("Green"));
|
||||||
static_assert_1(Channel::_is_valid_nocase("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().size() == 3);
|
||||||
static_assert_1(*Channel::_values().begin() == +Channel::Red);
|
static_assert_1(*Channel::_values().begin() == +Channel::Red);
|
||||||
static_assert_1(*(Channel::_values().end() - 1) == +Channel::Blue);
|
static_assert_1(*(Channel::_values().end() - 1) == +Channel::Blue);
|
||||||
static_assert_1(Channel::_values()[1] == +Channel::Green);
|
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
|
#ifdef BETTER_ENUMS_CONSTEXPR_TO_STRING
|
||||||
|
|
||||||
constexpr bool same_string(const char *r, const char *s, size_t index = 0)
|
constexpr bool same_string(const char *r, const char *s, size_t index = 0)
|
||||||
@ -136,6 +164,24 @@ static_assert_1(same_string(Depth::_names()[0], "HighColor"));
|
|||||||
|
|
||||||
|
|
||||||
// Run-time testing.
|
// 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 {
|
class EnumTests : public CxxTest::TestSuite {
|
||||||
public:
|
public:
|
||||||
void test_constant_values()
|
void test_constant_values()
|
||||||
@ -210,9 +256,9 @@ class EnumTests : public CxxTest::TestSuite {
|
|||||||
|
|
||||||
void test_value_iterable()
|
void test_value_iterable()
|
||||||
{
|
{
|
||||||
TS_ASSERT_EQUALS(Channel::_size, 3);
|
TS_ASSERT_EQUALS(Channel::_size(), 3);
|
||||||
TS_ASSERT_EQUALS(Depth::_size, 2);
|
TS_ASSERT_EQUALS(Depth::_size(), 2);
|
||||||
TS_ASSERT_EQUALS(Channel::_values().size(), Channel::_size);
|
TS_ASSERT_EQUALS(Channel::_values().size(), Channel::_size());
|
||||||
TS_ASSERT_EQUALS(*Channel::_values().begin(), +Channel::Red);
|
TS_ASSERT_EQUALS(*Channel::_values().begin(), +Channel::Red);
|
||||||
TS_ASSERT_EQUALS(*(Channel::_values().begin() + 1), +Channel::Green);
|
TS_ASSERT_EQUALS(*(Channel::_values().begin() + 1), +Channel::Green);
|
||||||
TS_ASSERT_EQUALS(*(Channel::_values().begin() + 2), +Channel::Blue);
|
TS_ASSERT_EQUALS(*(Channel::_values().begin() + 2), +Channel::Blue);
|
||||||
@ -237,7 +283,7 @@ class EnumTests : public CxxTest::TestSuite {
|
|||||||
|
|
||||||
void test_name_iterable()
|
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().begin(), "Red"), 0);
|
||||||
TS_ASSERT_EQUALS(strcmp(Channel::_names()[0], "Red"), 0);
|
TS_ASSERT_EQUALS(strcmp(Channel::_names()[0], "Red"), 0);
|
||||||
TS_ASSERT_EQUALS(strcmp(Depth::_names()[0], "HighColor"), 0);
|
TS_ASSERT_EQUALS(strcmp(Depth::_names()[0], "HighColor"), 0);
|
||||||
@ -269,4 +315,120 @@ class EnumTests : public CxxTest::TestSuite {
|
|||||||
{
|
{
|
||||||
TS_ASSERT_EQUALS(Compression::Default, Compression::Huffman);
|
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)
|
||||||
29
test/cxxtest/stream.h
Normal file
29
test/cxxtest/stream.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#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);
|
||||||
|
}
|
||||||
|
};
|
||||||
4
test/expect/102-any-underlying
Normal file
4
test/expect/102-any-underlying
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
Red component: c4
|
||||||
|
Green component: 74
|
||||||
|
Blue component: 51
|
||||||
|
darksalmon
|
||||||
@ -1,2 +0,0 @@
|
|||||||
ENUM(Channel, int, Red = 0, Green = 1, Blue = 2)
|
|
||||||
ENUM(Depth, int, TrueColor = 1, HighColor = 0)
|
|
||||||
2
test/expect/104-quine
Normal file
2
test/expect/104-quine
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
BETTER_ENUM(Channel, int, Red = 0, Green = 1, Blue = 2)
|
||||||
|
BETTER_ENUM(Depth, int, TrueColor = 1, HighColor = 0)
|
||||||
1
test/expect/105-c++17-reflection
Normal file
1
test/expect/105-c++17-reflection
Normal file
@ -0,0 +1 @@
|
|||||||
|
Blue
|
||||||
4
test/expect/5-map
Normal file
4
test/expect/5-map
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
the red channel
|
||||||
|
the red channel
|
||||||
|
Green
|
||||||
|
Blue
|
||||||
1
test/expect/6-iostreams
Normal file
1
test/expect/6-iostreams
Normal file
@ -0,0 +1 @@
|
|||||||
|
Red
|
||||||
@ -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>
|
|
||||||
|
|
||||||
ENUM(Channel, int, Red, Green, Blue)
|
|
||||||
|
|
||||||
#endif // #ifndef _SHARED_H_
|
|
||||||
@ -4,4 +4,5 @@
|
|||||||
void print(Channel channel)
|
void print(Channel channel)
|
||||||
{
|
{
|
||||||
std::cout << Channel::_name() << "::" << channel._to_string() << std::endl;
|
std::cout << Channel::_name() << "::" << channel._to_string() << std::endl;
|
||||||
|
std::cout << Channel::_size() << std::endl;
|
||||||
}
|
}
|
||||||
8
test/linking/helper.h
Normal file
8
test/linking/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/linking/shared.h
Normal file
8
test/linking/shared.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ifndef SHARED_H
|
||||||
|
#define SHARED_H
|
||||||
|
|
||||||
|
#include <enum.h>
|
||||||
|
|
||||||
|
BETTER_ENUM(Channel, int, Red, Green, Blue)
|
||||||
|
|
||||||
|
#endif // #ifndef SHARED_H
|
||||||
@ -1,219 +1,223 @@
|
|||||||
#include <enum.h>
|
#include <enum.h>
|
||||||
|
|
||||||
ENUM(Channel, int,
|
BETTER_ENUM(Channel, int,
|
||||||
Red, Green, Blue, Cyan, Magenta, Yellow, Black, Hue, Saturation, Value)
|
Red, Green, Blue, Cyan, Magenta, Yellow, Black, Hue, Saturation,
|
||||||
|
Value)
|
||||||
|
|
||||||
ENUM(Direction, int,
|
BETTER_ENUM(Direction, int,
|
||||||
North, East, South, West, NorthEast, SouthEast, SouthWest, NorthWest,
|
North, East, South, West, NorthEast, SouthEast, SouthWest,
|
||||||
NorthNorthEast, EastNorthEast, EastSouthEast, SouthSouthEast,
|
NorthWest, NorthNorthEast, EastNorthEast, EastSouthEast,
|
||||||
SouthSouthWest, WestSouthWest, WestNorthWest, NorthNorthWest)
|
SouthSouthEast, SouthSouthWest, WestSouthWest, WestNorthWest,
|
||||||
|
NorthNorthWest)
|
||||||
|
|
||||||
ENUM(ASTNode, int,
|
BETTER_ENUM(ASTNode, int,
|
||||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||||
BasicType, ArrowType, VariantTypeConstant)
|
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||||
|
|
||||||
ENUM(State, int,
|
BETTER_ENUM(State, int,
|
||||||
Attacking, Defending, Searching, Pursuing, Hungry, Fleeing, Confused,
|
Attacking, Defending, Searching, Pursuing, Hungry, Fleeing,
|
||||||
Healing, Stunned)
|
Confused, Healing, Stunned)
|
||||||
|
|
||||||
ENUM(APIMethod, int,
|
BETTER_ENUM(APIMethod, int,
|
||||||
ReadPost, WritePost, PollPost, ReadImage, WriteImage, PollImage, ReadKey,
|
ReadPost, WritePost, PollPost, ReadImage, WriteImage, PollImage,
|
||||||
WriteKey, PollKey, ReadUser, WriteUser, PollUser, ReadOrganization,
|
ReadKey, WriteKey, PollKey, ReadUser, WriteUser, PollUser,
|
||||||
WriteOrganization, PollOrganization, ReadGroup, WriteGroup, PollGroup,
|
ReadOrganization, WriteOrganization, PollOrganization, ReadGroup,
|
||||||
ReadProject, WriteProject, PollProject, ReadComment, WriteComment,
|
WriteGroup, PollGroup, ReadProject, WriteProject, PollProject,
|
||||||
PollComment, ReadPermission, WritePermission, PollPermission, ReadOwner,
|
ReadComment, WriteComment, PollComment, ReadPermission,
|
||||||
WriteOwner, PollOwner, ReadProposal, WriteProposal, PollProposal,
|
WritePermission, PollPermission, ReadOwner, WriteOwner, PollOwner,
|
||||||
ReadHistory, WriteHistory, PollHistory)
|
ReadProposal, WriteProposal, PollProposal, ReadHistory,
|
||||||
|
WriteHistory, PollHistory)
|
||||||
|
|
||||||
ENUM(Lipsum, int,
|
BETTER_ENUM(Lipsum, int,
|
||||||
Lorem, ipsum, dolor, sit, amet, consectetur, adipiscing, elit, Vivamus,
|
Lorem, ipsum, dolor, sit, amet, consectetur, adipiscing, elit,
|
||||||
libero, massa, tincidunt, at, ex, nec, porta, malesuada, arcu, Nullam,
|
Vivamus, libero, massa, tincidunt, at, ex, nec, porta, malesuada,
|
||||||
lectus, nibh, dictum, eget, convallis, ac, feugiat, felis, Suspendisse,
|
arcu, Nullam, lectus, nibh, dictum, eget, convallis, ac, feugiat,
|
||||||
quis, purus, vel, lacus, cursus, tristique, Donec, augue, tortor, luctus,
|
felis, Suspendisse, quis, purus, vel, lacus, cursus, tristique,
|
||||||
a, sed, mattis, in, quam, Cras, vitae, euismod, Cum, sociis, natoque,
|
Donec, augue, tortor, luctus, a, sed, mattis, in, quam, Cras, vitae,
|
||||||
penatibus, et, magnis, dis, parturient)
|
euismod, Cum, sociis, natoque, penatibus, et, magnis, dis,
|
||||||
|
parturient)
|
||||||
|
|
||||||
ENUM(ASTNode0, int,
|
BETTER_ENUM(ASTNode0, int,
|
||||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||||
BasicType, ArrowType, VariantTypeConstant)
|
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||||
|
|
||||||
ENUM(ASTNode1, int,
|
BETTER_ENUM(ASTNode1, int,
|
||||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||||
BasicType, ArrowType, VariantTypeConstant)
|
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||||
|
|
||||||
ENUM(ASTNode2, int,
|
BETTER_ENUM(ASTNode2, int,
|
||||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||||
BasicType, ArrowType, VariantTypeConstant)
|
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||||
|
|
||||||
ENUM(ASTNode3, int,
|
BETTER_ENUM(ASTNode3, int,
|
||||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||||
BasicType, ArrowType, VariantTypeConstant)
|
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||||
|
|
||||||
ENUM(ASTNode4, int,
|
BETTER_ENUM(ASTNode4, int,
|
||||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||||
BasicType, ArrowType, VariantTypeConstant)
|
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||||
|
|
||||||
ENUM(ASTNode5, int,
|
BETTER_ENUM(ASTNode5, int,
|
||||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||||
BasicType, ArrowType, VariantTypeConstant)
|
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||||
|
|
||||||
ENUM(ASTNode6, int,
|
BETTER_ENUM(ASTNode6, int,
|
||||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||||
BasicType, ArrowType, VariantTypeConstant)
|
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||||
|
|
||||||
ENUM(ASTNode7, int,
|
BETTER_ENUM(ASTNode7, int,
|
||||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||||
BasicType, ArrowType, VariantTypeConstant)
|
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||||
|
|
||||||
ENUM(ASTNode8, int,
|
BETTER_ENUM(ASTNode8, int,
|
||||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||||
BasicType, ArrowType, VariantTypeConstant)
|
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||||
|
|
||||||
ENUM(ASTNode9, int,
|
BETTER_ENUM(ASTNode9, int,
|
||||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||||
BasicType, ArrowType, VariantTypeConstant)
|
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||||
|
|
||||||
ENUM(ASTNode10, int,
|
BETTER_ENUM(ASTNode10, int,
|
||||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||||
BasicType, ArrowType, VariantTypeConstant)
|
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||||
|
|
||||||
ENUM(ASTNode11, int,
|
BETTER_ENUM(ASTNode11, int,
|
||||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||||
BasicType, ArrowType, VariantTypeConstant)
|
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||||
|
|
||||||
ENUM(ASTNode12, int,
|
BETTER_ENUM(ASTNode12, int,
|
||||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||||
BasicType, ArrowType, VariantTypeConstant)
|
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||||
|
|
||||||
ENUM(ASTNode13, int,
|
BETTER_ENUM(ASTNode13, int,
|
||||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||||
BasicType, ArrowType, VariantTypeConstant)
|
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||||
|
|
||||||
ENUM(ASTNode14, int,
|
BETTER_ENUM(ASTNode14, int,
|
||||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||||
BasicType, ArrowType, VariantTypeConstant)
|
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||||
|
|
||||||
ENUM(ASTNode15, int,
|
BETTER_ENUM(ASTNode15, int,
|
||||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||||
BasicType, ArrowType, VariantTypeConstant)
|
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||||
|
|
||||||
ENUM(ASTNode16, int,
|
BETTER_ENUM(ASTNode16, int,
|
||||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||||
BasicType, ArrowType, VariantTypeConstant)
|
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||||
|
|
||||||
ENUM(ASTNode17, int,
|
BETTER_ENUM(ASTNode17, int,
|
||||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||||
BasicType, ArrowType, VariantTypeConstant)
|
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||||
|
|
||||||
ENUM(ASTNode18, int,
|
BETTER_ENUM(ASTNode18, int,
|
||||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||||
BasicType, ArrowType, VariantTypeConstant)
|
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||||
|
|
||||||
ENUM(ASTNode19, int,
|
BETTER_ENUM(ASTNode19, int,
|
||||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||||
BasicType, ArrowType, VariantTypeConstant)
|
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||||
|
|
||||||
ENUM(ASTNode20, int,
|
BETTER_ENUM(ASTNode20, int,
|
||||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||||
BasicType, ArrowType, VariantTypeConstant)
|
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||||
|
|
||||||
ENUM(ASTNode21, int,
|
BETTER_ENUM(ASTNode21, int,
|
||||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||||
BasicType, ArrowType, VariantTypeConstant)
|
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||||
|
|
||||||
ENUM(ASTNode22, int,
|
BETTER_ENUM(ASTNode22, int,
|
||||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||||
BasicType, ArrowType, VariantTypeConstant)
|
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||||
|
|
||||||
ENUM(ASTNode23, int,
|
BETTER_ENUM(ASTNode23, int,
|
||||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||||
BasicType, ArrowType, VariantTypeConstant)
|
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||||
|
|
||||||
ENUM(ASTNode24, int,
|
BETTER_ENUM(ASTNode24, int,
|
||||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||||
BasicType, ArrowType, VariantTypeConstant)
|
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||||
|
|
||||||
ENUM(ASTNode25, int,
|
BETTER_ENUM(ASTNode25, int,
|
||||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||||
BasicType, ArrowType, VariantTypeConstant)
|
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||||
|
|
||||||
ENUM(ASTNode26, int,
|
BETTER_ENUM(ASTNode26, int,
|
||||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||||
BasicType, ArrowType, VariantTypeConstant)
|
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||||
|
|
||||||
ENUM(ASTNode27, int,
|
BETTER_ENUM(ASTNode27, int,
|
||||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||||
BasicType, ArrowType, VariantTypeConstant)
|
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||||
|
|
||||||
ENUM(ASTNode28, int,
|
BETTER_ENUM(ASTNode28, int,
|
||||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||||
BasicType, ArrowType, VariantTypeConstant)
|
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||||
|
|
||||||
ENUM(ASTNode29, int,
|
BETTER_ENUM(ASTNode29, int,
|
||||||
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
|
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
|
||||||
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
|
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
|
||||||
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
|
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
|
||||||
BasicType, ArrowType, VariantTypeConstant)
|
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
|||||||
272
test/test.py
272
test/test.py
@ -1,272 +0,0 @@
|
|||||||
#! /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