Compare commits

..

No commits in common. "master" and "0.9.0" have entirely different histories.

90 changed files with 1370 additions and 4721 deletions

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
*.h linguist-language=C++
*.tmpl linguist-language=HTML

1
.github/FUNDING.yml vendored
View File

@ -1 +0,0 @@
github: aantron

2
.gitignore vendored
View File

@ -5,4 +5,4 @@ scratch/
doc/html/
doc-publish/
test/cxxtest/*.cc
test/build
test/platform/

View File

@ -1,38 +0,0 @@
language: cpp
env:
- COMPILER="clang++-3.7"
- COMPILER="g++-5"
- COMPILER="g++-4.6"
- COMPILER="g++-4.7"
- COMPILER="g++-4.4"
- COMPILER="g++-4.8"
- COMPILER="g++-4.9"
- COMPILER="clang++-3.3"
- COMPILER="clang++-3.4"
- COMPILER="clang++-3.5"
- COMPILER="clang++-3.6"
matrix:
allow_failures:
- env: COMPILER="clang++-3.3"
- env: COMPILER="clang++-3.5"
before_script:
- sudo add-apt-repository --yes ppa:ubuntu-toolchain-r/test
- sudo add-apt-repository --yes ppa:h-rayflood/llvm
- sudo add-apt-repository -y 'deb http://llvm.org/apt/precise/ llvm-toolchain-precise-3.5 main'
- sudo add-apt-repository -y 'deb http://llvm.org/apt/precise/ llvm-toolchain-precise-3.6 main'
- sudo add-apt-repository -y 'deb http://llvm.org/apt/precise/ llvm-toolchain-precise-3.7 main'
- sudo apt-get update -qq
- sudo apt-get install --allow-unauthenticated $COMPILER
- git clone https://github.com/CxxTest/cxxtest.git cxxtest-ro
- curl -O https://cmake.org/files/v3.2/cmake-3.2.3-Linux-x86_64.tar.gz
- tar -xzf cmake-3.2.3-Linux-x86_64.tar.gz
- sudo cp -fR cmake-3.2.3-Linux-x86_64/* /usr
script:
- export PATH="$PATH:$(pwd)/cxxtest-ro/bin"
- ln -s cxxtest-ro/cxxtest cxxtest
- cd test
- make COMPILER=$COMPILER unix

View File

@ -1,4 +1,4 @@
Copyright (c) 2012-2024, Anton Bachin
Copyright (c) 2012-2015, Anton Bachin
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,

119
README.md
View File

@ -1,21 +1,39 @@
# Better Enums   [![Try online][wandbox-img]][wandbox] [![Travis status][travis-img]][travis] [![AppVeyor status][appveyor-img]][appveyor]
# Better Enums
[wandbox]: http://melpon.org/wandbox/permlink/2QCi3cwQnplAToge
[wandbox-img]: https://img.shields.io/badge/try%20it-online-blue.svg
[appveyor]: https://ci.appveyor.com/project/aantron/better-enums/branch/master
[travis]: https://travis-ci.org/aantron/better-enums/branches
[travis-img]: https://img.shields.io/travis/aantron/better-enums/master.svg?label=travis
[appveyor-img]: https://img.shields.io/appveyor/ci/aantron/better-enums/master.svg?label=appveyor
[license-img]: https://img.shields.io/badge/license-BSD-lightgrey.svg
Reflective compile-time C++ enum library with clean syntax, in a single header
file. For example:
Reflective compile-time enum library with clean syntax, in a single header
file, and without dependencies.
#include <enum.h>
ENUM(Channel, int, Red = 1, Green, Blue)
![Better Enums code overview][sample]
defines a type `Channel`. You can then do natural things such as:
[sample]: https://raw.githubusercontent.com/aantron/better-enums/master/doc/image/sample.gif
```cpp
Channel channel = Channel::Green;
In C++11, *everything* can be used at compile time. You can convert your enums,
channel._to_string(); // Results in the string "Green"
Channel::_from_string("Red"); // Results in Channel::Red
Channel::_from_integral(3); // Checked cast, Channel::Blue
Channel::_size; // Number of channels (3)
Channel::_values()[0]; // Get the first channel
for (Channel channel : Channel::_values()) {
process(channel); // Iterate over all channels
}
// Natural switch, compiler checks the cases
switch (channel) {
case Channel::Red: break;
case Channel::Green: break;
case Channel::Blue: break;
}
```
...and more.
In C++11, *everything* is available at compile time. You can convert your enums,
loop over them, [find their max][max],
[statically enforce conventions][enforce], and pass along the results as
template arguments or to `constexpr` functions. All the reflection is available
@ -31,73 +49,36 @@ See the [project page][project] for full documentation.
[enforce]: http://aantron.github.io/better-enums/demo/SpecialValues.html
[project]: http://aantron.github.io/better-enums
<br/>
## Installation
Simply add `enum.h` to your project.
Simply add `enum.h` to your project &mdash; that's it.
<br/>
Then, include it and use the `ENUM` macro. Your compiler will generate the rich
enums that are missing from standard C++.
## Additional features
- Uses only standard C++, though, for C++98, variadic macro support is required
(major compilers have it).
- Supported and tested on [clang, gcc, and msvc][testing].
- No dependencies and no external build tools. Uses only standard C++, though,
for C++98, variadic macro support is required.
- Supported and tested on clang, gcc, and msvc.
- Fast compilation. You have to declare a few dozen enums to slow down your
compiler as much as [only including `iostream` does][performance].
- Use any initializers and sparse ranges, just like with a built-in enum.
- Control over size and alignment &mdash; you choose the representation type.
- Stream operators.
- Does not use the heap and can be compiled with exceptions disabled, for use in
minimal freestanding environments.
compiler as much as [just including `iostream` does][performance].
- Use any initializers, just like with a built-in enum.
- Guaranteed size and alignment &mdash; you choose the representation type.
[testing]: http://aantron.github.io/better-enums/CompilerSupport.html
[performance]: http://aantron.github.io/better-enums/Performance.html
<br/>
## Contact
## Limitations
Don't hesitate to contact me about features or bugs:
[antonbachin@yahoo.com](mailto:antonbachin@yahoo.com), or open an issue on
GitHub.
1. The biggest limitation is that the `BETTER_ENUM` macro can't be used inside a
class. This seems [difficult to remove][nested]. There is a workaround with
`typedef` (or C++11 `using`):
## License and history
```c++
BETTER_ENUM(SomePrefix_Color, uint8_t, Red, Green, Blue)
Better Enums is released under the BSD 2-clause license. See
[LICENSE](https://github.com/aantron/better-enums/blob/master/LICENSE).
struct triplet {
typedef SomePrefix_Color Color;
Color r, g, b;
};
triplet::Color color;
```
You can, however, use `BETTER_ENUM` inside a namespace.
2. The macro has a soft limit of 64 declared constants. You can extend it by
following [these instructions][extend]. Ultimately, the number of constants is
limited by your compiler's maximum macro argument count.
3. In some cases, it is necessary to prefix constants such as `Channel::Red` with a
`+` to explicitly promote them to type `Channel`. For example, if you are doing
a comparison:
```c++
channel == +Channel::Red
```
4. On msvc, you may need to enable [warning C4062][C4062] to get `switch` case exhaustiveness checking.
[nested]: http://aantron.github.io/better-enums/DesignDecisionsFAQ.html#NoEnumInsideClass
[extend]: http://aantron.github.io/better-enums/ExtendingLimits.html
[C4062]: https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-4-c4062
<br/>
## History
The original version of the library was developed by the author in the winter of
2012-2013 at Hudson River Trading, as a replacement for an older generator
called `BETTER_ENUM`.
The library was originally developed by the author in the winter of 2012-2013 at
Hudson River Trading, as a replacement for an older generator called
`BETTER_ENUM`.

View File

@ -1,29 +0,0 @@
version: "{build}"
branches:
except:
- gh-pages
- traits
skip_tags : true
shallow_clone: true
os: Visual Studio 2017
environment:
matrix:
- TITLE: vc2017
COMPILER: Visual Studio 15 2017
- TITLE: vc2015
COMPILER: Visual Studio 14 2015
- TITLE: vc2013
COMPILER: Visual Studio 12 2013
install:
- git clone --depth 1 https://github.com/CxxTest/cxxtest.git
build_script:
- set CL=/I C:\projects\better-enums\cxxtest
- set PATH=%PATH%;C:\projects\better-enums\cxxtest\bin;C:\cygwin\bin
- cd test
- make ms

View File

@ -7,7 +7,7 @@ $internal_toc
The declaration
#include <enum.h>
<em>BETTER_ENUM</em>(<em>Enum</em>, <em>underlying_type</em>, <em>A</em>, <em>B</em>, <em>C</em>, ...)
<em>ENUM</em>(<em>Enum</em>, <em>underlying_type</em>, <em>A</em>, <em>B</em>, <em>C</em>, ...)
generates a new class type `Enum` which is notionally similar to the type
created by this $cxx11 declaration:
@ -20,29 +20,29 @@ That is, `Enum` is a scoped enumerated type with constants `Enum::A`, `Enum::B`,
`Enum::C`, and so on, with memory representation the same as `underlying_type`.
It is possible to supply initializers for any of the constants:
<em>BETTER_ENUM</em>(Enum, underlying_type, <em>A</em> = <em>1</em>, <em>B</em> = <em>constant_expression</em>, <em>C</em> = <em>A</em>, ...)
<em>ENUM</em>(Enum, underlying_type, <em>A</em> = <em>1</em>, <em>B</em> = <em>constant_expression</em>, <em>C</em> = <em>A</em>, ...)
The initializers have the same meaning and constraints as in a built-in `enum`
or `enum class` declaration.
---
The principal differences between the types declared by the `BETTER_ENUM` macro
and `enum class` are:
The principal differences between the types declared by the `ENUM` macro and
`enum class` are:
- `BETTER_ENUM` is available for $cxx98
- `ENUM` is available for $cxx98
[compilers](${prefix}CompilerSupport.html) supporting `__VA_ARGS__` &mdash;
all major compilers &mdash; while `enum class` is restricted to $cxx11,
- the `BETTER_ENUM` type is implicitly convertible to integral types, though
this can be [disabled](${prefix}OptInFeatures.html#StrictConversions) when
using $cxx11, and
- the `BETTER_ENUM` type supports a set of reflective operations, detailed in
the rest of this reference.
- the `ENUM` type is implicitly convertible to integral types, though this can
be [disabled](${prefix}OptInFeatures.html#StrictConversions) when using
$cxx11, and
- the `ENUM` type supports a set of reflective operations, detailed in the
rest of this reference.
---
The types produced by the `BETTER_ENUM` macro are called *Better Enums* in the
rest of this reference.
The types produced by the `ENUM` macro are called *Better Enums* in the rest of
this reference.
Better Enums are similar to their underlying type for the purposes of argument
passing. This means that they typically fit into a machine word, and should be
@ -57,7 +57,7 @@ in order to avoid conflicts with potential constant names.
The rest of this reference uses the following declaration as a running example:
<em>BETTER_ENUM</em>(<em>Enum</em>, <em>int</em>, <em>A</em>, <em>B</em>, <em>C</em>)
<em>ENUM</em>(<em>Enum</em>, <em>int</em>, <em>A</em>, <em>B</em>, <em>C</em>)
@ -69,8 +69,8 @@ rest of the documentation.
#### <em>typedef _enumerated</em>
An internal type used to declare constants. The `BETTER_ENUM` macro generates
something similar to
An internal type used to declare constants. The `ENUM` macro generates something
similar to
~~~comment
<em>struct Enum</em> {
@ -150,14 +150,9 @@ using <em>optional</em> = <em>better_enums::optional</em>&lt;<em>Enum</em>&gt;;
The types and members described here have to do with the sequence of constants
declared, i.e. `A`, `B`, `C` in the [running example](#RunningExample).
#### static constexpr size_t <em>_size</em>()
#### static constexpr size_t <em>_size</em>
The number of constants declared. `Enum::_size() == 3`.
#### static constexpr const size_t <em>_size_constant</em>
Same as [`_size`](#_size), but a constant instead of a function. This is
provided for use in $cxx98 constant expressions.
The number of constants declared. `Enum::_size == 3`.
#### <em>typedef _value_iterable</em>
@ -228,7 +223,7 @@ If the given string is the exact name of a declared constant, returns the
constant. Otherwise, throws `std::runtime_error`. Running time is linear in the
number of declared constants multiplied by the length of the longest constant.
#### static constexpr optional&lt;Enum&gt; <em>_from_string_nothrow</em>(const char*)
#### static constexpr optional<Enum> <em>_from_string_nothrow</em>(const char*)
Same as [`_from_string`](#_from_string), but does not throw an exception on
failure. Returns an [optional value](#StructBetter_enumsoptional) instead.
@ -238,7 +233,7 @@ failure. Returns an [optional value](#StructBetter_enumsoptional) instead.
Same as [`_from_string`](#_from_string), but comparison is up to case, in the
usual sense in the Latin-1 encoding.
#### static constexpr optional&lt;Enum&gt; <em>_from_string_nocase_nothrow</em>(const char*)
#### static constexpr optional<Enum> <em>_from_string_nocase_nothrow</em>(const char*)
Is to [`_from_string_nocase`](#_from_string_nocase) as
[`_from_string_nothrow`](#_from_string_nothrow) is to
@ -260,7 +255,7 @@ case as in [`_from_string_nocase`](#_from_string_nocase).
Evaluates to the name of the Better Enum type. `Enum::_name()` is the same
string as `"Enum"`.
#### <em>typedef _name_iterable</em>
#### typedef <em>_name_iterable</em>
Type of object that permits iteration over names of declared constants. Has at
least `constexpr` `begin()`, `end()`, and `size()` methods. `operator[]` is also
@ -268,7 +263,7 @@ available, but is `constexpr` if and only if [`_to_string`](#_to_string) is
`constexpr`. Iteration visits constants in order of declaration. See usage
example under [`_names`](#_names).
#### <em>typedef _name_iterator</em>
#### typedef <em>_name_iterator</em>
Random-access iterator type for `_name_iterable`. Most operations are
`constexpr`, but dereferencing is `constexpr` if and only if
@ -327,7 +322,7 @@ example,
(+<em>Enum::C</em>)<em>._to_integral</em>() == <em>2</em>
Note that Better Enums are already implicitly convertible to their underlying
integral types [by default](${prefix}OptInFeatures.html#StrictConversions).
integral types [by default](${prefix}OptInFeatures.html#StrictConversion).
You may still want to use this function, however, for clarity, and to ensure
that your code remains compatible if the strict conversions feature is enabled
later.
@ -342,7 +337,7 @@ of one of the declared constants.
<em>Enum::_from_integral</em>(<em>2</em>); // Enum::C
<em>Enum::_from_integral</em>(<em>42</em>); // std::runtime_error
#### static constexpr optional&lt;Enum&gt; <em>_from_integral_nothrow</em>(_integral)
#### static constexpr optional<Enum> <em>_from_integral_nothrow</em>(_integral)
Checked conversion as [`_from_integral`](#_from_integral), but does not throw an
exception on failure. Returns an [optional value](#StructBetter_enumsoptional)
@ -370,64 +365,6 @@ constants.
### Index lookup
#### member constexpr std::size_t <em>_to_index</em>() const
Returns the index of a Better Enum value within its enum declaration. The index
is determined from the value only; if two constants in the declaration have the
same value, this function may return the index of either constant.
If the value does not correspond to any constant in the declaration (for
example, if it was obtained using an unchecked conversion or a cast), then the
behavior of `value._to_index` is undefined.
#### static constexpr Enum <em>_from_index</em>(size_t)
Returns the value of the constant with the given index. Throws
`std::runtime_error` if not given the index of one of the constants.
#### static constexpr Enum <em>_from_index_unchecked</em>(size_t)
Returns the value of the constant with the given index. If not given one of the
constants in the declaration of the enum, the returned value is undefined.
#### static constexpr optional&lt;Enum&gt; <em>_from_index_nothrow</em>(size_t)
Returns the value of the constant with the given index.
### Stream operators
#### non-member std::ostream& <em>operator <<</em>(std::ostream&, const Enum&)
Formats the given enum to the given stream in the same way as
[`_to_string`](#_to_string).
#### non-member std::istream& <em>operator >></em>(std::istream&, Enum&)
Reads from the given stream and attempts to parse an enum value in the same way
as [`_from_string`](#_from_string). In case of failure, sets the stream's
`failbit`.
### Hashing
#### macro <em>BETTER_ENUMS_DECLARE_STD_HASH</em>(Enum)
Use this outside namespace scope to declare a specialization of `std::hash` for
the type `Enum`. For example:
// This declaration might be inside a namespace.
<em>BETTER_ENUM</em>(<em>Channel</em>, int, Red, Green, Blue)
// Later, outside the namespace:
<em>BETTER_ENUMS_DECLARE_STD_HASH</em>(<em>Channel</em>)
%% class = api
%% description = Detailed description of the Better Enums API.

View File

@ -1,94 +0,0 @@
# Contributing to Better Enums
All contributions are welcome: feedback, documentation changes, and, of course,
pull requests and patch suggestions. A list of contributors is maintained in the
`CONTRIBUTORS` file. I am grateful to everyone mentioned.
## Some major outstanding issues
- Better Enums currently uses linear scans for lookup, so it could really
benefit from a lookup data structure that is really fast to generate at
compile time. All the sorts and other approaches I have tried so far,
including MPL, Meta, and my own, have been 10-50 times too slow for practical
use.
- Alternatively, if there is a method to detect whether a given function is
running at compile or run time, Better Enums could use linear scans during
compilation, then do a sort at program initialization, and then use fast
lookups.
- It would be nice if name trimming was always `constexpr`. Right now, this is
not the default, because it makes compilation of each Better Enum about four
times slower. Better Enums needs a fast way to take a `const char*`, chop off
any initializers, and return the new `const char*`.
- I would like to enable more warning flags besides just
`-Wall -Wextra -pedantic`, but CxxTest triggers the extra warnings.
`CMakeLists.txt` should probably be modified to add the extra warnings to all
targets that are not CxxTest tests.
## Testing
I typically write small programs to play around with `enum.h`. The `scratch/`
directory is in `.gitignore` for this purpose. Create `scratch/` and feel free
to do anything you want in it. Once your change is nearly complete, you should
run the automated test suite.
While still actively developing, run `make -C test` to do quick builds. Before
submitting your pull request, run `make -C test default-all`. The first command
tests your code on your system compiler in one configuration, and the second
command tests it in all configurations that your compiler supports.
*Configurations* refers to the optional features of Better Enums, such as
`constexpr` string conversion and using an `enum class` for `switch` statements.
Once your pull request is submitted, the [AppVeyor][appveyor] and
[Travis][travis] web services will automatically test it on many versions of
GCC, Clang, and Visual C++. If you have more than one compiler installed
locally, you can run either the `unix` or `ms` target in `test/Makefile` to test
on a specific compiler. Open the `Makefile` file and find the targets for
instructions.
If your pull request does not include any changes to the code (for example, you
have changed only documentation), add the text `[ci skip]` to the commit message
to prevent AppVeyor and Travis from testing the commit.
The `make` targets mentioned above depend on the following software:
- Make
- CMake
- Python 2
- [CxxTest][cxxtest]
CxxTest's `bin/` directory has to be in `PATH` and the root `cxxtest/` directory
has to be in whatever environment variable your system compiler uses to search
for header files.
On Windows, you also need [Cygwin][cygwin]. The directory containing
`MSBuild.exe` must be in `PATH`.
The programs in `example/` are generated from the Markdown files in
`doc/tutorial/` and `doc/demo/`. If you have edited the Markdown files, you
should run `make -C test examples` to update the example program sources.
If you have created a new example program or compilation performance test, add
it to `test/CMakeLists.txt`. Search for the name of an existing program, such as
`1-hello-world`, and you should see where to add new ones.
[cygwin]: https://www.cygwin.com
[cxxtest]: http://cxxtest.com
[appveyor]: https://ci.appveyor.com/project/aantron/better-enums
[travis]: https://travis-ci.org/aantron/better-enums
## Commits
Please write descriptive commit messages that follow the 50/72 rule. I am likely
to edit commit messages when merging into `master`. I will also squash multiple
commits in most cases. If you prefer I not do either one, let me know, but then
we will have to go back and forth on the exact contents of the pull request.
I am maintaining the `master` branch in such a way that every commit passes its
tests, i.e. `master` is always stable. Every commit going into `master` is first
fully tested in its pull request branch, or in a temporary staging branch, if
necessary.
## Generating the documentation
To generate an offline copy of the documentation, run `make -C doc`. To view it,
open `doc/html/index.html`.

View File

@ -1,11 +0,0 @@
Here you will find a list of everyone I have to thank for contributing code,
suggestions, comments, other feedback, or anything else that was useful to the
library. This file never shrinks - if a name goes missing, it's because a chat
handle was replaced by a real name. There is no significance to the order.
Thanks to:
Tony Van Eerd
Ben Alex
Simon Stienen
Alexander Buddenbrock

View File

@ -1,10 +1,11 @@
## Compiler support
Better Enums aims to support all major compilers. It is known to work on:
Better Enums aims to support all major compilers. It is known to definitely work
on
- clang 3.3 to 3.9
- gcc 4.3 to 5.3
- Visual C++ 2008 to 2015.
- clang 3.3 to 3.6
- gcc 4.3 to 5.1
- Visual C++ 2013U4, 2015RC.
The library can be used with any compiler that supports either $cxx11, or $cxx98
with the `__VA_ARGS__` extension. This includes every version of gcc and clang I
@ -75,21 +76,6 @@ vc2015 /EHsc
vc2015 /EHsc /DBETTER_ENUMS_STRICT_CONVERSION
vc2013 /EHsc
vc2013 /EHsc /DBETTER_ENUMS_STRICT_CONVERSION
vc2012 /EHsc
vc2010 /EHsc
vc2008 /EHsc
clang++39 -std=c++11
clang++39 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
clang++39 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
clang++39 -std=c++98
clang++38 -std=c++11
clang++38 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
clang++38 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
clang++38 -std=c++98
clang++37 -std=c++11
clang++37 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
clang++37 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
clang++37 -std=c++98
clang++36 -std=c++11
clang++36 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
clang++36 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
@ -102,11 +88,14 @@ clang++34 -std=c++11
clang++34 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
clang++34 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
clang++34 -std=c++98
clang++33 -std=c++11
clang++33 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
clang++33 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
clang++33 -std=c++98
g++53 -std=c++11
g++53 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
g++53 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
g++53 -std=c++98
g++51 -std=c++11
g++51 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
g++51 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
g++51 -std=c++98
g++49 -std=c++11
g++49 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
g++49 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
@ -119,12 +108,17 @@ g++47 -std=c++11
g++47 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
g++47 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
g++47 -std=c++98
g++46 -std=c++0x -DBETTER_ENUMS_NO_CONSTEXPR
g++46 -std=c++0x -DBETTER_ENUMS_NO_CONSTEXPR -DBETTER_ENUMS_STRICT_CONVERSION
g++46 -std=c++98
g++45 -std=c++0x -DBETTER_ENUMS_NO_CONSTEXPR
g++45 -std=c++0x -DBETTER_ENUMS_NO_CONSTEXPR -DBETTER_ENUMS_STRICT_CONVERSION
g++45 -std=c++98
g++44 -std=c++0x -DBETTER_ENUMS_NO_CONSTEXPR
g++44 -std=c++0x -DBETTER_ENUMS_NO_CONSTEXPR -DBETTER_ENUMS_STRICT_CONVERSION
g++44 -std=c++98
g++43 -std=c++0x -DBETTER_ENUMS_NO_CONSTEXPR
g++43 -std=c++98
~~~
%% description =
Better Enums compiler support, compatibility, feature detection, and automated
testing.
%% description = Information about compiler support and feature detection.

15
doc/Contact.md Normal file
View File

@ -0,0 +1,15 @@
## Contact
- Send me an email: [antonbachin@yahoo.com](mailto:antonbachin@yahoo.com).
- Visit the [GitHub]($repo) project to open an issue or get a development
version.
I also watch the `enums` tag on Stack Overflow.
I'm happy to hear any feedback. If you have any trouble using the library or
parsing the documentation, please don't hesitate to let me know.
And, if you find this library helpful, give it a star on GitHub to let me know
you use it. It will help keep me encouraged :)
%% description = Contact information for bugs, issues, support, and feedback.

View File

@ -1,269 +0,0 @@
## Design decisions FAQ
$be pushes at the edges of what is possible in standard $cxx, and I've had to
make some difficult decisions as a result. You can imagine the set of
potential reflective enum implementations as a space, with axes such as "concise
syntax," "uniform interface," "compilation speed," "run-time performance," and
so on. As is typical in engineering, the constraints are such that as you move
to extremes along one axis, you have to retreat along others &mdash; 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 &mdash; 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 &mdash; 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 &mdash; 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.

View File

@ -1,8 +1,8 @@
## Extending limits
The `BETTER_ENUM` macro makes heavy use of the preprocessor, and some of the
internal macros have size limits. There are two: on the number of constants you
can declare, and on the maximum length of a constant name under very specific
The `ENUM` macro makes heavy use of the preprocessor, and some of the internal
macros have size limits. There are two: on the number of constants you can
declare, and on the maximum length of a constant name under very specific
conditions. If you run into either one, you can extend the limit by following
the instructions on this page.
@ -19,7 +19,7 @@ constants of full-`constexpr` enums. To extend:
example. Add 1 to the number of characters to account for the null
terminator &mdash; our numbers are now 512 and 64.
2. Get `make_macros.py` from your copy of the full Better Enums distribution
or from <a href="https://raw.githubusercontent.com/aantron/better-enums/$ref/script/make_macros.py" download>GitHub</a>.
or from <a href="https://raw.githubusercontent.com/aantron/better-enums/$version/script/make_macros.py" download>GitHub</a>.
3. You will run this script to generate a header file containing some
replacement macros for `enum.h` to use. Pick a name for this file and a
location somewhere in your include path. I will assume that this file is
@ -31,38 +31,10 @@ constants of full-`constexpr` enums. To extend:
- For g++ and clang++, `-DBETTER_ENUMS_MACRO_FILE='<common/enum_macros.h>'`
- For VC++, `\DBETTER_ENUMS_MACRO_FILE='<common/enum_macros.h>'`
- With CMake, you may need something like
`add_definitions(-DBETTER_ENUMS_MACRO_FILE="$${CMAKE_SOURCE_DIR}/src/enum-macros.h")`
You can also create a new header file that defines this macro, and then
includes `enum.h`. Then, include your new file everywhere where you would
otherwise include `enum.h`:
~~~comment
<em>#pragma once
#define BETTER_ENUMS_MACRO_FILE <common/enum_macros.h>
#include <enum.h></em>
~~~
6. Enjoy the looser limits. Just watch out &mdash; increasing the second
number can really slow down compilation of full-`constexpr` enums.
7. You don't need `make_macros.py` anymore. It's not part of your build
process and you can delete it.
---
I am paying attention to feedback, so if more than a few users say that the
default limit of 64 constants is too low, I will increase it to simplify
everyone's command line. The current choice of 64 is basically an arbitrary
guess, loosely informed by the following two facts about macro parameter limits:
- The default limit in Boost.Preprocessor is 64. Though Better Enums does not
use Boost, I took this number as a guideline.
- The next power of two, 128, is more than [the number Visual C++ supports][vc]
(127).
[vc]: https://msdn.microsoft.com/en-us/library/ft39hh4x.aspx
%% description =
How to extend limits imposed by internal macros in Better Enums.
%% description = How to extend limits imposed by internal macros.

View File

@ -1,36 +1,23 @@
toexample = ../example/$(notdir $(1:.md=.cc))
SOURCE_MARKDOWN := $(wildcard tutorial/*) $(wildcard demo/*)
SOURCE_CXX := $(SOURCE_MARKDOWN:.md=.cc)
SOURCE_MARKDOWN := $(wildcard tutorial/*.md) $(wildcard demo/*.md)
SOURCE_CXX := $(foreach md,$(SOURCE_MARKDOWN),$(call toexample,$(md)))
.PHONY : all
all : html examples
.PHONY : html
html :
python docs.py
@echo "See html/index.html"
.PHONY : publish
publish : prepare
cp -r html/* ../doc-publish
cd ../doc-publish && git add . && git commit --amend --reset-author && \
git push -f
.PHONY : prepare
prepare : examples web
.PHONY : web
web : examples
python docs.py --web
.PHONY : examples
examples : $(SOURCE_CXX)
examples : clean-examples $(SOURCE_CXX)
define EXAMPLE
$(1) : $(2)
python transform.py --o-cxx $(1) $(2)
endef
.PHONY : clean-examples
clean-examples :
make -C ../example clean
rm -f ../example/*.cc
$(foreach md,$(SOURCE_MARKDOWN), \
$(eval $(call EXAMPLE,$(call toexample,$(md)),$(md))))
%.cc : %.md
python transform.py --o-cxx ../example/$(notdir $@) $<
.PHONY : clean
clean :

View File

@ -6,27 +6,6 @@ default. Read this page if you want to enable them.
$internal_toc
### Default constructors
Better Enums generate with inaccessible (private or deleted) default
constructors. This is meant to help control where in your program Better Enums
values are introduced, and thus ensure that only valid, properly initialized
enum values are ever created.
If you want Better Enums to have a default constructor, you can do something
like the following:
~~~
<em>#define</em> <em>BETTER_ENUMS_DEFAULT_CONSTRUCTOR</em>(<em>Enum</em>) \
<em>public</em>: \
<em>Enum()</em> = <em>default</em>;
<em>#include</em> <<em>enum.h</em>>
~~~
You can put this in its own header file, and include that header file instead of
including `enum.h` directly.
### Compile-time name trimming
This makes `_to_string` and `_names` `constexpr`, i.e. "full" `constexpr` mode.
@ -43,8 +22,7 @@ slow enums to get the same penalty as including `iostream` &mdash; but it is
a steep penalty nonetheless. I don't think most people need this feature most of
the time, so it's too high a price to pay. If I improve compilation times to the
point where compile-time name trimming can be the default, I will simply
redefine `SLOW_ENUM` as `BETTER_ENUM` and deprecate it, so your code will still
work.
redefine `SLOW_ENUM` as `ENUM` and deprecate it, so your code will still work.
### Strict conversions
@ -86,17 +64,5 @@ Here they are:
case <em>+</em>Channel::Blue: break;
}
%% description = Optional Better Enums features, disabled by default for
performance or compatibility reasons.
### Injecting tokens
You can define `BETTER_ENUMS_CLASS_ATTRIBUTE` before declaring a Better Enum, to
inject tokens into the class declaration. For example, in
#define <em>BETTER_ENUMS_CLASS_ATTRIBUTE</em> <em>__attribute__(foo)</em>
<em>BETTER_ENUM</em>(<em>Channel</em>, int, Red, Green, Blue)
The resulting enum declaration will begin with
class <em>__attribute__(foo)</em> <em>Channel</em> {
%% description = Opting into features disabled by default for performance or
compatibility reasons.

View File

@ -7,9 +7,9 @@ to get a rough idea of how long it takes to compile Better Enums.
The files compared in the test are as follows:
- [One file]($repo/blob/$ref/test/performance/4-declare_enums.cc) includes
- [One file]($repo/blob/$version/test/performance/4-declare_enums.cc) includes
`enum.h` and declares 647 constants across 36 Better Enums.
- The [other file]($repo/blob/$ref/test/performance/5-iostream.cc) *only*
- The [other file]($repo/blob/$version/test/performance/5-iostream.cc) *only*
includes `iostream` and does nothing with it.
The argument is that if compiling a bunch of Better Enums is faster, or about as
@ -29,22 +29,4 @@ compiled faster.
- gcc 5.1, full `constexpr`: 4.23
- VC2015RC, $cxx98: 1.18
The time to merely include `enum.h` vary widely by compiler, with clang being
by far the fastest. The ratios to `iostream` are given below.
- clang 3.6: 0.15
- gcc 5.1: 0.77
- VC2015RC: 0.82
On my test machines, clang processed the file in 40ms, gcc took 230ms, and
VC2015 took 820ms. The first two are comparable to each other, but VC2015 runs
on a different machine.
---
In general, I am very sensitive to performance. Better Enums was originally
developed in the context of a commercial project where slow running times *and*
slow compilation times were unacceptable. I am continuing to develop it in this
spirit.
%% description = Better Enums compilation speed and performance testing results.
%% description = Compilation performance testing results.

View File

@ -11,19 +11,13 @@ pre, code, samp, h4, .contents ul {
Consolas, "Liberation Mono", Menlo, "Courier New", Courier, monospace;
}
h1, .splash-text .self, nav .self {
font-family: Georgia, Times, "Times New Roman", serif;
}
pre {
background-color: #477093;
padding: 1.5em 20px;
border-radius: 5px;
overflow: auto;
overflow: scroll;
color: rgba(255, 255, 255, 0.6);
font-size: 78%;
max-width: 84ex;
margin-left: 1em;
}
pre em {
@ -51,35 +45,21 @@ code, samp {
}
.container {
margin-left: 150px;
margin-right: 150px;
max-width: 760px;
margin-left: 230px;
}
.main .container > * {
max-width: 41em;
}
.index .main .container > * {
max-width: none;
}
.main .container > .contents {
max-width: none;
}
@media (max-width: 1400px) {
@media (max-width: 1220px) {
.container {
margin-left: auto;
margin-right: auto;
width: 1100px;
}
}
@media (max-width: 1120px) {
@media (max-width: 780px) {
.container {
margin-left: 10px;
margin-right: 10px;
width: auto;
}
}
@ -99,17 +79,6 @@ nav, .spacer {
background-color: #222;
}
nav > * > span {
float: right;
opacity: 0.9;
margin-right: 1em;
}
nav .self {
font-size: 16px;
padding-right: 0.5em;
}
nav a {
margin-right: 2em;
}
@ -134,38 +103,13 @@ header {
background: linear-gradient(#395E7E, #4A79A0);
color: white;
padding: 50px 0;
margin-bottom: 50px;
}
h1 {
margin: 0;
font-size: 60px;
font-weight: normal;
text-shadow: -2px 2px rgba(0, 0, 0, 0.3);
}
header section {
float: left;
}
header section.buttons, header section.notes {
float: right;
margin-top: 1.75em;
margin-left: 20px;
}
header section.notes {
max-width: 20em;
font-size: 75%;
margin-right: 10px;
opacity: 0.7;
}
header section.notes p {
margin: 0.35em 0.35em;
}
header section.notes code {
background-color: transparent;
font-weight: 100;
}
header h2 {
@ -185,41 +129,10 @@ header h3 {
opacity: 0.5;
}
.buttons a {
display: block;
background-color: rgba(255, 255, 255, 0.2) !important;
width: 10em;
text-align: center;
margin-bottom: 0.5em;
padding: 0.25em 0;
border-radius: 4px;
}
.buttons a:hover {
background-color: white !important;
color: #395E7E;
}
@media (max-width: 1000px) {
header .notes {
display: none;
}
header .buttons {
margin-right: 2em;
}
}
@media (max-width: 660px) {
header .buttons {
display: none;
}
}
h2 {
margin-top: 2em;
font-size: 36px;
font-weight: 300;
font-weight: 100;
}
hr {
@ -229,20 +142,20 @@ hr {
footer {
font-size: 14px;
margin-top: 100px;
margin-top: 150px;
margin-bottom: 20px;
opacity: 0.5;
opacity: 0.6;
}
a {
text-decoration: none;
color: white;
/*background-color: red;*/
background-color: red;
}
a[href=""] {
color: white !important;
/*background-color: red !important;*/
background-color: red !important;
}
a:hover {
@ -253,10 +166,6 @@ header a:hover {
text-decoration: none;
}
.main {
margin-top: 50px;
}
.main a[href], footer a[href] {
background-color: #edd;
color: #844;
@ -306,6 +215,7 @@ span#note:target {
.main h3 {
font-size: 30px;
font-weight: 100;
margin-top: 2em;
color: black;
}
@ -378,45 +288,15 @@ li {
}
.blurbs > li {
width: 45%;
float: left;
min-height: 5em;
}
@media (min-width: 1076px) {
.blurbs > li {
width: 28%;
margin-right: 4%;
}
.blurbs > li.zero-mod-three {
.blurbs > li.even {
clear: both;
margin-left: 2%;
}
}
@media (max-width: 1075px) {
.blurbs > li {
width: 45%;
margin-right: 4%;
}
.blurbs > li.zero-mod-two {
clear: both;
margin-left: 2%;
}
}
@media (max-width: 620px) {
.blurbs > li {
float: none;
width: 100%;
min-height: 3em;
}
.blurbs > li.zero-mod-two {
margin-left: 0;
margin-right: 0;
}
margin-left: 3%;
margin-right: 6%;
}
.blurbs strong {
@ -431,6 +311,19 @@ li {
font-style: normal;
}
@media (max-width: 620px) {
.blurbs > li {
float: none;
width: 100%;
min-height: 3em;
}
.blurbs > li.even {
margin-left: 0;
margin-right: 0;
}
}
.act strong {
font-weight: bold;
font-size: 120%;
@ -449,25 +342,9 @@ li {
padding-left: 25px;
}
.splash-text {
padding-top: 1em;
font-size: 150%;
font-weight: normal;
color: #555;
}
.splash-text em {
border-bottom: 1px solid #888;
}
.splash-text .self {
color: #777;
letter-spacing: 0;
}
.splash {
float: right;
text-align: center;
margin-left: -10%;
white-space: nowrap;
}
@ -477,22 +354,12 @@ li {
.splash pre.left {
text-align: right;
color: black;
font-weight: bold;
color: inherit;
background-color: transparent;
padding-right: 0;
}
.splash pre.right {
text-align: left;
background-color: black;
}
@media (max-width: 1000px) {
.splash {
float: none;
margin-left: -10%;
}
}
@media (max-width: 700px) {
@ -518,7 +385,6 @@ h4 {
color: #888;
padding-top: 1em;
white-space: nowrap;
font-size: 125%;
}
h4 em {
@ -528,9 +394,9 @@ h4 em {
}
.api ul.contents {
-webkit-columns: 300px 3;
-moz-columns: 300px 3;
columns: 300px 3;
-webkit-columns: 300px 2;
-moz-columns: 300px 2;
columns: 300px 2;
}
.api ul.contents > li {
@ -541,7 +407,6 @@ h4 em {
.main h3 {
margin-top: 4em;
clear: both;
}
h3.contents {
@ -560,36 +425,3 @@ h3.contents {
margin-top: 0;
padding-bottom: 1em;
}
.buttons-bar {
background-color: #f4f4f4;
padding-top: 0.5em;
padding-bottom: 0.5em;
height: 20px;
}
.buttons-bar a img {
margin-right: 25px;
}
.buttons-bar iframe.gh-button {
width: 95px;
}
.buttons-bar .tweet-share,
.buttons-bar .gh-button {
display: none;
}
.index .buttons-bar .tweet-share,
.index .buttons-bar .gh-button {
display: initial;
}
.buttons-bar iframe.gh-watch {
width: 103px;
}
.external {
font-size: 75%;
}

View File

@ -46,10 +46,10 @@ A macro allows us to override the invalid value by specializing the template:
Now, we can declare enums like these:
BETTER_ENUM(<em>Channel</em>, int, Red, Green, Blue, <em>Invalid</em>)
ENUM(<em>Channel</em>, int, Red, Green, Blue, <em>Invalid</em>)
// Invalid is the invalid value by default
BETTER_ENUM(<em>Compression</em>, int, <em>Undefined</em>, None, Huffman)
ENUM(<em>Compression</em>, int, <em>Undefined</em>, None, Huffman)
OVERRIDE_INVALID(<em>Compression</em>, <em>Undefined</em>)
and use them:
@ -71,7 +71,7 @@ slightly more complex template function for the general case:
constexpr <em>Enum default_imp</em>l()
{
return
<em>Enum::_size() < 2 ?
<em>Enum::_size < 2 ?
throw std::logic_error("enum has no valid constants") :
Enum::_values()[0] == invalid_impl<Enum>() ?
Enum::_values()[1] :
@ -100,7 +100,7 @@ And, as before, the usage:
And, if you do
BETTER_ENUM(<em>Answer</em>, int, Yes, No, <em>Invalid</em>)
ENUM(<em>Answer</em>, int, Yes, No, <em>Invalid</em>)
// OVERRIDE_DEFAULT(<em>Answer</em>, <em>Invalid</em>)
you will get a helpful compile-time error saying
@ -170,6 +170,5 @@ There are many possible variations of these policies, but I think most of them
can be encoded in a reasonable fashion using the tools Better Enums provides.
Enjoy!
%% description = An example that uses Better Enums compile-time reflection to
create invalid and default values for each enum, enforced statically by the
compiler, for readability and maintainability.
%% description = Encoding project policies for static enforcement using Better
Enums.

View File

@ -17,7 +17,7 @@ We simply need to find the maximum value of any given enum type.
constexpr <em>Enum max_loop</em>(Enum accumulator, size_t index)
{
return
<em>index >= Enum::_size() ? accumulator :
<em>index >= Enum::_size ? accumulator :
Enum::_values()[index] > accumulator ?
max_loop<Enum>(Enum::_values()[index], index + 1) :
max_loop<Enum>(accumulator, index + 1)</em>;
@ -38,7 +38,7 @@ Now, we can have bit sets that are wide enough to hold whatever range we
declared. We just declare enums, and the numeric values of their constants will
be bit indices. The rest is straightforward.
BETTER_ENUM(<em>EFLAGS</em>, int,
ENUM(<em>EFLAGS</em>, int,
<em>Carry</em>, <em>Parity</em> = 2, <em>Adjust</em> = 4, <em>Zero</em>, <em>Sign</em>, <em>Trap</em>, <em>Interrupt</em>, <em>Direction</em>,
<em>Overflow</em>, <em>NestedTask</em> = 14, <em>Resume</em> = 16, <em>V8086</em>, <em>AlignmentCheck</em>,
<em>CPUIDPresent</em> = 21)
@ -65,5 +65,5 @@ static_assert(max<EFLAGS>()._to_integral() < 32,
"some bit indices are out of range");
~~~
%% description = Finding the maximum value of a Better Enum for use in declaring
statically-sized bit set types.
%% description = Finding the maximum value of a Better Enum constant for use in
declaring bit set types.

View File

@ -8,7 +8,7 @@ buffer for the definition at compile time.
Ok, so it's not really a quine, because we won't be writing all the code needed
to generate the definition to the buffer as well. And, there are better ways to
dump the definition than shown here. You could simply define a macro that
expands to an `BETTER_ENUM` declaration and also stringizes it.
expands to an `ENUM` declaration and also stringizes it.
But that's not the point here. The point of this page is to show some of the
reflective capabilities of Better Enums, so you can adapt them for cases where a
@ -37,8 +37,8 @@ since we will be calling `_to_string`. Let's make sure it's enabled by defining
Now, let's declare some enums to dump later:
BETTER_ENUM(<em>Channel</em>, int, Red, Green, Blue)
BETTER_ENUM(<em>Depth</em>, int, TrueColor = 1, HighColor = 0)
ENUM(<em>Channel</em>, int, Red, Green, Blue)
ENUM(<em>Depth</em>, int, TrueColor = 1, HighColor = 0)
@ -82,7 +82,7 @@ initializers for sequential values, but I won't go through this exercise here.
constexpr <em>size_t constants_length</em>(size_t index = 0, size_t accumulator = 0)
{
return
<em>index >= Enum::_size() ? accumulator :
<em>index >= Enum::_size ? accumulator :
constants_length<Enum>(
index + 1, accumulator
+ string_length(", ")
@ -102,7 +102,7 @@ the whole enum:
constexpr <em>size_t declaration_length</em>()
{
return
<em>string_length("BETTER_ENUM(")
<em>string_length("ENUM(")
+ string_length(Enum::_name())
+ string_length(", int")
+ constants_length<Enum>()
@ -129,7 +129,7 @@ so that we can do a sanity check on it.
{
size_t offset = 0;
offset += std::sprintf(buffer, <em>"BETTER_ENUM(%s, int", Enum::_name()</em>);
offset += std::sprintf(buffer, <em>"ENUM(%s, int", Enum::_name()</em>);
<em>for</em> (<em>Enum value</em> : <em>Enum::_values()</em>) {
offset +=
@ -166,10 +166,8 @@ Now, we can write and run this code.
It prints:
~~~comment
BETTER_ENUM(Channel, int, Red = 0, Green = 1, Blue = 2)
BETTER_ENUM(Depth, int, TrueColor = 1, HighColor = 0)
ENUM(Channel, int, Red = 0, Green = 1, Blue = 2)
ENUM(Depth, int, TrueColor = 1, HighColor = 0)
~~~
%% description = Have a Better Enum print its own definition. Shows how to
compute the amount of memory necessary from the reflective information provided
by a Better Enum.
%% description = Contrived example that shows static memory allocation.

View File

@ -1,173 +0,0 @@
## C++17 reflection proposal
*You can try this demo [live online][live].*
Better Enums can be used to implement the enums portion of the
[$cxx17 reflection proposal N4428][n4428] in $cxx11. N4428 proposes the
following traits interface:
~~~comment
<em>namespace std {
template <typename E>
struct enum_traits {
struct enumerators {
constexpr static size_t size;
template <size_t I>
struct get {
constexpr string_literal identifier;
constexpr static E value;
};
};
};
}</em>
~~~
So, the basic usage would be:
~~~comment
<em>enum class Foo {A, B, C};
constexpr size_t size =
std::enum_traits<Foo>::enumerators::size;
constexpr Foo value_0 =
std::enum_traits<Foo>::enumerators::get<0>::value;
constexpr string_literal name_1 =
std::enum_traits<Foo>::enumerators::get<1>::identifier;</em>
~~~
Resulting in the values `3`, `Foo::A`, and `"B"`, respectively.
---
The interface is implemented in the optional header file
[`extra/better-enums/n4428.h`][header]. There is a necessary difference: the
interface is only available for enums declared through the `BETTER_ENUM` macro.
This is because the macro is what generates the information necessary for
reflection.
### Demo
So, with that out of the way, we can do a little test. Let's assume that
`extra/` has been added as a directory to search for include files.
#ifndef BETTER_ENUMS_CONSTEXPR_TO_STRING
#define BETTER_ENUMS_CONSTEXPR_TO_STRING
#endif
#include <iostream>
<em>#include</em> <<em>enum.h</em>>
<em>#include</em> <<em>better-enums/n4428.h</em>>
---
Let's declare an enum:
<em>BETTER_ENUM</em>(<em>Channel</em>, <em>char</em>, <em>Red</em> = <em>1</em>, <em>Green</em>, <em>Blue</em>)
...and try N4428:
constexpr std::size_t <em>size</em> =
<em>std</em>::<em>enum_traits</em><<em>Channel</em>>::<em>enumerators</em>::<em>size</em>;
constexpr Channel <em>value_0</em> =
<em>std</em>::<em>enum_traits</em><<em>Channel</em>>::<em>enumerators</em>::<em>get</em><<em>0</em>>::<em>value</em>;
constexpr Channel <em>value_1</em> =
<em>std</em>::<em>enum_traits</em><<em>Channel</em>>::<em>enumerators</em>::<em>get</em><<em>1</em>>::<em>value</em>;
constexpr const char *<em>identifier_2</em> =
<em>std</em>::<em>enum_traits</em><<em>Channel</em>>::<em>enumerators</em>::<em>get</em><<em>2</em>>::<em>identifier</em>;
...and check the results:
static_assert(<em>size</em> == <em>3</em>, "");
static_assert(<em>value_0</em> == +<em>Channel::Red</em>, "");
static_assert(<em>value_1</em> == +<em>Channel::Green</em>, "");
int main()
{
std::cout << <em>identifier_2</em> << std::endl;
return 0;
}
That prints `Blue`, as you would expect.
### Quirk
The reason for the `#define` in the code above is that there is one quirk:
the interface above is available only for Better Enums for which
[compile-time name trimming][slow-enum] is enabled &mdash; 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.

View File

@ -7,8 +7,6 @@ import string
import transform
import os
import os.path
import sys
import urllib
TEMPLATE_DIRECTORY = "template"
OUTPUT_DIRECTORY = "html"
@ -85,24 +83,15 @@ def compose_page(relative_path, definitions):
definitions["canonical"] = canonical
definitions["prefix"] = prefix
definitions["quoted_url"] = urllib.quote(definitions["canonical"], "")
definitions["quoted_title"] = urllib.quote(definitions["title"], "")
if "class" not in definitions:
definitions["class"] = ""
text = templates["page"]
text = scrub_comments(text)
while True:
new_text = scrub_comments(text)
new_text = re.sub("\$\$", "$$$$", new_text)
new_text = apply_template(new_text, definitions)
if new_text == text:
text = apply_template(new_text, definitions)
break
text = new_text
while '$' in text:
text = apply_template(text, definitions)
text = scrub_comments(text)
text = "<!-- Generated automatically - edit the templates! -->\n\n" + text
@ -140,9 +129,7 @@ def compose_general_page(relative_path):
write_page(relative_path, text)
def list_general_pages():
return filter(
lambda s: not os.path.splitext(os.path.basename(s))[0].isupper(),
glob.glob("*.md"))
return glob.glob("*.md")
def process_threaded(directory):
sources = glob.glob(os.path.join(directory, "*.md"))
@ -156,7 +143,7 @@ def process_threaded(directory):
source_file = \
os.path.splitext(os.path.basename(file))[0] + "." + CXX_EXTENSION
source_link = "$repo/blob/$ref/example/" + source_file
source_link = "$repo/blob/$version/example/" + source_file
definitions[directory + "_body"] = definitions["body"]
definitions["body"] = templates[directory]
@ -196,10 +183,6 @@ def generate_sitemap():
for url in generated:
text += " <url>\n"
text += " <loc>%s</loc>\n" % url
if ".html" not in url:
text += " <priority>1.0</priority>\n"
text += " </url>\n"
text += "</urlset>\n"
@ -209,9 +192,6 @@ def generate_sitemap():
def main():
load_templates()
if not (len(sys.argv) >= 2 and sys.argv[1] == "--web"):
templates["ga"] = ""
remove_output_directory()
process_threaded(TUTORIAL_DIRECTORY)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

View File

@ -1,3 +1,9 @@
Better Enums is a single header file that causes your compiler to generate
*reflective* enum types. This makes it easy to translate between enums and
strings, and much more.
Here's how to use a Better Enum:
<div class="splash">
<pre class="left">enable
@ -5,7 +11,7 @@ declare
parse
format
print
count
@ -13,7 +19,6 @@ iterate
switch
@ -24,25 +29,22 @@ switch
safe cast
during
compilation
</pre>
<pre class="right"><em>#include &lt;enum.h&gt;</em>
at compile time</pre>
<pre class="right"><em>#include</em> &lt;<em>enum.h</em>&gt;
<em>BETTER_ENUM(Channel, int, Red = 1, Green, Blue)</em>
<em>ENUM</em>(<em>Channel</em>, <em>int</em>, <em>Red</em> = <em>1</em>, <em>Green</em>, <em>Blue</em>)
Channel c = <em>Channel::_from_string("Red")</em>;
const char *s = <em>c._to_string()</em>;
size_t n = <em>Channel::_size()</em>;
<em>for (Channel c : Channel::_values())</em> {
run_some_function(c);
}
size_t n = <em>Channel::_size</em>;
<em>for</em> (<em>Channel c</em> : <em>Channel::_values()</em>)
run_some_function(<em>c</em>);
<em>switch (c)</em> {
<em>switch</em> (<em>c</em>) {
<em>case Channel::Red</em>: // ...
<em>case Channel::Green</em>: // ...
<em>case Channel::Blue</em>: // ...
@ -52,90 +54,17 @@ size_t n = <em>Channel::_size()</em>;
Channel c = <em>Channel::_from_integral(3)</em>;
<em>constexpr</em> Channel c =
<em>Channel::_from_string("Blue")</em>;</pre>
<em>constexpr</em> Channel c = <em>Channel::_from_string("Blue")</em>;</pre>
</div>
<p class="splash-text">
$be is a single, lightweight header file that makes your compiler generate
<em>reflective</em> enum types.
</p>
That means you can easily convert enums to and from strings,
validate them, and loop over them. In $cxx11, you can do it all at
compile time.
It's what built-in enums ought to support. Better Enums simply adds the missing
features. And, it is based on the best known techniques, thoroughly tested,
fast, portable, and documented exhaustively.
To use it, just include <code>enum.h</code> and begin the
[tutorial](${prefix}tutorial/HelloWorld.html)!
<div class="hack"></div>
### Highlights
### What do you get?
<ul class="blurbs">
<li class="zero-mod-two zero-mod-three">
<strong>Unobtrusive syntax</strong>
<em>
No ugly macros. Use initializers as with built-in <code>enums</code>.
Internal members have underscores to avoid clashing with your constant
names.
</em>
<li class="even">
<strong>Uniform interface for $cxx98 and $cxx11</strong>
<em>Scoped, sized, reflective enums for $cxx98.</em>
</li>
<li class="one-mod-two one-mod-three">
<strong>No external dependencies</strong>
<em>
Uses only standard $cxx. Installation is simple &mdash; just download
<code>enum.h</code>. There are no objects or libraries to link with.
</em>
</li>
<li class="zero-mod-two two-mod-three">
<strong>No generator program needed</strong>
<em>
Just include <code>enum.h</code>. It's a metaprogram executed by your
compiler.
</em>
</li>
<li class="one-mod-two zero-mod-three">
<strong>Plays nice with <code>switch</code></strong>
<em>
Use a Better Enum like a built-in <code>enum</code>, and still have the
compiler do case checking.
</em>
</li>
<li class="zero-mod-two one-mod-three">
<strong>Don't repeat yourself</strong>
<em>
No more unmaintanable maps or <code>switch</code> statements for
converting enums to strings.
</em>
</li>
<li class="one-mod-two two-mod-three">
<strong>Non-contiguous sequences</strong>
<em>
Iteration and counting are much easier to maintain than with an extra
<code>Count</code> constant and assuming a dense range.
</em>
</li>
<li class="zero-mod-two zero-mod-three">
<strong>Fast compilation</strong>
<em>
Much less impact on build time than even just including
<code>iostream</code>. <code>enum.h</code> is only slightly more than 1000
lines long.
</em>
</li>
<li class="one-mod-two one-mod-three">
<li>
<strong>Compile-time reflection</strong>
<em>
Have the compiler do additional enum processing using your own
@ -143,23 +72,60 @@ To use it, just include <code>enum.h</code> and begin the
</em>
</li>
<li class="zero-mod-two two-mod-three">
<strong>Uniform interface for $cxx98, $cxx11</strong>
<li class="even">
<strong>Non-contiguous sequences</strong>
<em>
Scoped, sized, reflective enums for $cxx98, and an easy upgrade
path.
Iteration and count much easier to maintain than with an extra "count"
constant and making assumptions.
</em>
</li>
<li>
<strong>Plays nice with <code>switch</code></strong>
<em>
Use a Better Enum like a built-in <code>enum</code>, and still have the
compiler do case checking.
</em>
</li>
<li class="one-mod-two zero-mod-three">
<strong>Stream operators</strong>
<li class="even">
<strong>Unobtrusive syntax</strong>
<em>
Write enum names directly to <code>std::cout</code> or use
<code>boost::lexical_cast</code>.
No ugly macros. Use initializers just like with built-in
<code>enums</code>. Generated members have underscores to avoid conflicts
with your constant names.
</em>
</li>
<li>
<strong>Don't repeat yourself</strong>
<em>
No more unmaintanable maps or <code>switch</code> statements for
converting enums to strings.
</em>
</li>
<li class="zero-mod-two one-mod-three">
<li class="even">
<strong>No build-time generator needed</strong>
<em>
Just include <code>enum.h</code>. It's a metaprogram executed by your
compiler.
</em>
</li>
<li>
<strong>Fast compilation</strong>
<em>
Much less impact on build time than even just including
<code>iostream</code>.
</em>
</li>
<li class="even">
<strong>No external dependencies</strong>
<em>
Uses standard $cxx and supported on major compilers. Installation is
simple &mdash; just download <code>enum.h</code>.
</em>
</li>
<li>
<strong>Free and open source</strong>
<em>
Released under the BSD license for use in any project, free or commercial.
@ -169,18 +135,40 @@ To use it, just include <code>enum.h</code> and begin the
<div class="hack"></div>
### Documentation
### It's what built-in enums ought to do.
The library notionally <em>extends</em> $cxx, adding oft-needed features.
<ul class="blurbs act">
<li class="even">
<strong>Download <a $download><code>enum.h</code></a></strong>
<em>
Current version: $version<br />
To install, just add the file to your project.
</em>
</li>
<li>
<strong>Visit on <a href="$repo">GitHub</a></strong>
<em>
Follow development, report issues, and let me know if you find this
library useful!
</em>
</li>
</ul>
<div class="hack"></div>
### Resources
<ul class="blurbs resources">
<li class="zero-mod-two zero-mod-three">
<li class="even">
<a id="Tutorial"></a>
<strong>Tutorial</strong>
<ol>
$tutorial_toc
</ol>
</li>
<li class="one-mod-two one-mod-three">
<li>
<strong>Reference</strong>
<ul>
<li><a href="${prefix}ApiReference.html">API reference</a></li>
@ -188,20 +176,12 @@ To use it, just include <code>enum.h</code> and begin the
<li><a href="${prefix}OptInFeatures.html">Opt-in features</a></li>
<li><a href="${prefix}ExtendingLimits.html">Extending limits</a></li>
<li><a href="${prefix}Performance.html">Performance</a></li>
<li>
<a href="${prefix}DesignDecisionsFAQ.html">Design decisions FAQ</a>
</li>
<li>
<a href="http://www.codeproject.com/Articles/1002895/Clean-Reflective-Enums-Enum-to-String-with-Nice-Sy">
Implementation <span class="external">[CodeProject]</span>
</a>
</li>
</ul>
</li>
<li class="zero-mod-two two-mod-three">
<li class="even">
<a id="CompileTimeDemos"></a>
<strong>Advanced</strong>
<strong>Compile-time demos</strong>
<ul>
$demo_toc
</ul>
@ -212,8 +192,8 @@ To use it, just include <code>enum.h</code> and begin the
%% title = Clean reflective enums for C++
%% description = Reflective enums in a single header file, with clean syntax.
The enums can be converted to string, iterated, and counted, at run time or
as part of metaprogramming. Free and open source under the BSD license.
%% description = Reflective enums for C++ with clean syntax, in a header-only
library. Can be converted to strings, iterated, counted, and used for
metaprogramming. Free under the BSD license.
%% class = index

File diff suppressed because it is too large Load Diff

10
doc/sitemap.xml Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>http://aantron.github.io/better-enums</loc>
<priority>1.0</priority>
</url>
<url>
<loc>http://aantron.github.io/better-enums/api.html</loc>
</url>
</urlset>

View File

@ -1 +0,0 @@
<span class="cpp">C++</span><span class="eleven">14</span>

View File

@ -1 +0,0 @@
<span class="cpp">C++</span><span class="eleven">17</span>

View File

@ -1,7 +1,7 @@
<p>
This is an example of code you can write on top of Better Enums. It's a valid
program &mdash; you can <a href="$source">download</a> it and try it out. The
program is also part of the test suite.
This page is an advanced demo showing the kind of compile-time code you can
write on top of Better Enums. You can <a href="$source">download</a> it and
try it out.
</p>
$demo_body

View File

@ -1,2 +1,2 @@
href="https://raw.githubusercontent.com/aantron/better-enums/$ref/enum.h"
href="https://raw.githubusercontent.com/aantron/better-enums/$version/enum.h"
download

View File

@ -3,9 +3,8 @@
<footer>
<div class="container">
Copyright &copy; 2015-2024 Anton Bachin. Released under the BSD 2-clause
license. See
<a href="https://github.com/aantron/better-enums/blob/$ref/doc/LICENSE">
Copyright &copy; 2015 Anton Bachin. Released under the BSD 2-clause license.
See <a href="https://github.com/aantron/better-enums/blob/master/LICENSE">
LICENSE</a>.
<br />
This page is part of the documentation for Better Enums $version.

10
doc/template/ga.tmpl vendored
View File

@ -1,10 +0,0 @@
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-62962513-1', 'auto');
ga('send', 'pageview');
</script>

View File

@ -1 +0,0 @@
<iframe src="https://ghbtns.com/github-btn.html?user=aantron&repo=better-enums&type=fork&count=true" frameborder="0" scrolling="0" width="170px" height="20px" class="gh-button"></iframe>

View File

@ -1 +0,0 @@
<iframe src="https://ghbtns.com/github-btn.html?user=aantron&repo=better-enums&type=star&count=true" frameborder="0" scrolling="0" width="170px" height="20px" class="gh-button"></iframe>

View File

@ -1 +0,0 @@
<iframe src="https://ghbtns.com/github-btn.html?user=aantron&repo=better-enums&type=watch&count=true&v=2" frameborder="0" scrolling="0" height="20px" class="gh-watch gh-button"></iframe>

View File

@ -13,8 +13,6 @@
<link rel="stylesheet" href="${prefix}better-enums.css" />
$ga
</head>
<body class="$class">
@ -25,6 +23,7 @@ $ga
<a href="${prefix}index.html">Home</a>
<a href="${prefix}tutorial/HelloWorld.html">Tutorial</a>
<a href="${prefix}ApiReference.html">Reference</a>
<a href="${prefix}Contact.html">Contact</a>
</div>
</nav>
@ -32,24 +31,11 @@ $ga
<header>
<div class="container">
<section>
<div class="back">{}</div>
<h1><a href="${prefix}index.html">Better Enums</a></h1>
<h2>Reflective compile-time enums for $cxx</h2>
<h3>Open-source under the BSD license</h3>
</section>
<section class="notes">
<p>Version $version</p>
<p>To install, just add <code>enum.h</code> to your project.</p>
<p>
Visit the GitHub repo for issues, feedback, and the latest development.
</p>
</section>
<section class="buttons">
<a $download>Download <code>enum.h</code></a>
<a href="$repo">GitHub</a>
</section>
</div>
</header>

View File

@ -1 +0,0 @@
0.11.3

View File

@ -1,7 +1,6 @@
<p>
Welcome to the Better Enums tutorials! The code in this tutorial forms a
valid program, which you can <a href="$source">download</a> and play with. The
program runs as part of the automated test suite.
valid program, which you can <a href="$source">download</a> and play with.
</p>
$tutorial_body

View File

@ -1 +1 @@
0.11.3
0.9.0

View File

@ -50,7 +50,7 @@ def camel_case(text):
components = re.split("[ -]+", text)
components = map(lambda s: s.capitalize(), components)
result = "".join(components)
result = filter(lambda c: c not in ",!:-$()?", result)
result = filter(lambda c: c not in ",!:-$()", result)
return result
class HtmlRenderer(mistune.Renderer):

View File

@ -1,11 +1,11 @@
## Hello, World!
Download <a $download><code>enum.h</code></a>, then compile this program:
Download <a $download><code>enum.h</code></a>, then build this program with it:
#include <iostream>
<em>#include "enum.h"</em>
<em>BETTER_ENUM</em>(<em>Word</em>, <em>int</em>, <em>Hello</em>, <em>World</em>)
<em>ENUM</em>(<em>Word</em>, <em>int</em>, <em>Hello</em>, <em>World</em>)
int main()
{
@ -20,5 +20,4 @@ Run it, and you should see the output "Hello, World!"
Congratulations, you have just created your first Better Enum!
%% description = Introductory Better Enums tutorial - a simple, but complete,
Hello World program.
%% description = Introductory Better Enums tutorial.

View File

@ -7,7 +7,7 @@ Let's begin by including `enum.h` and declaring our enum:
<em>#include <enum.h></em>
<em>BETTER_ENUM</em>(<em>Channel</em>, <em>int</em>, <em>Cyan</em> = <em>1</em>, <em>Magenta</em>, <em>Yellow</em>, <em>Black</em>)
<em>ENUM</em>(<em>Channel</em>, <em>int</em>, <em>Cyan</em> = <em>1</em>, <em>Magenta</em>, <em>Yellow</em>, <em>Black</em>)
We now have an `int`-sized enum with four constants.
@ -149,6 +149,4 @@ reference has a
return 0;
}
%% description = Better Enums conversion functions. Converting to string, from
string, to int, from int, and validation, both case-sensitive and
case-insensitive. Exception-throwing and non-throwing variants presented.
%% description = Walkthrough of Better Enums conversion functions.

View File

@ -6,12 +6,12 @@ example, this:
#include <iostream>
#include <enum.h>
<em>BETTER_ENUM(Channel, int, Red, Green = 2, Blue)</em>
<em>ENUM(Channel, int, Red, Green = 2, Blue)</em>
int main()
{
<em>for</em> (<em>size_t index = 0</em>; <em>index < Channel::_size()</em>; <em>++index</em>) {
<em>for</em> (<em>size_t index = 0</em>; <em>index < Channel::_size</em>; <em>++index</em>) {
Channel channel = <em>Channel::_values()[index]</em>;
std::cout << channel._to_integral() << " ";
}
@ -19,7 +19,7 @@ example, this:
will print "0 2 3". And this:
<em>for</em> (<em>size_t index = 0</em>; <em>index < Channel::_size()</em>; <em>++index</em>) {
<em>for</em> (<em>size_t index = 0</em>; <em>index < Channel::_size</em>; <em>++index</em>) {
const char *name = <em>Channel::_names()[index]</em>;
std::cout << name << " ";
}
@ -46,5 +46,4 @@ If you are using $cxx11, you can have much nicer syntax:
return 0;
}
%% description = Using Better Enums to iterate over all the constants of an
enum, as well as over its names. Also shows the same with C++11 for-each syntax.
%% description = Iterating over all Better Enums constants.

View File

@ -5,7 +5,7 @@ A Better Enum can be used directly in a `switch` statement:
#include <iostream>
<em>#include <enum.h></em>
<em>BETTER_ENUM(Channel, int, Red, Green, Blue)</em>
<em>ENUM(Channel, int, Red, Green, Blue)</em>
int main()
{
@ -21,16 +21,10 @@ A Better Enum can be used directly in a `switch` statement:
If you miss a case or add a redundant one, your compiler should be able to give
you a warning &mdash; try it!
Note that on msvc, you may need to enable [warning C4062][C4062].
[C4062]: https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-4-c4062
---
std::cout << n << std::endl;
return 0;
}
%% description = Better Enums can be used directly in switch statements like
normal enums, making it possible for the compiler to check that all cases are
listed, increasing the safety of your code.
%% description = Usage in switch statements.

View File

@ -1,77 +0,0 @@
## Maps
It is possible to create `constexpr` bidirectional maps between Better Enums and
any type. This is currently an experimental feature. Feedback is very much
wanted, but please don't build any mission-critical code on top of this :)
The way it works is you give Better Enums a function &mdash; 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 &mdash; 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.

View File

@ -3,12 +3,6 @@
This tutorial shows some of the safety features of Better Enums: scope, how to
control conversions, and the lack of a default constructor.
On balance, Better Enums are in one way less type-safe than enum class, and in
another way more type-safe. The first difference in safety is the presence of
implicit conversion to integral types. The second difference is the lack of a
default constructor. Both of these can be toggled, so you can make Better Enums
strictly safer than enum class, or just as safe.
$internal_toc
### Scope
@ -18,7 +12,7 @@ You have probably noticed by now that Better Enums are scoped: when you declare
#include <cassert>
<em>#include <enum.h></em>
<em>BETTER_ENUM</em>(<em>Channel</em>, <em>int</em>, <em>Red</em> = <em>1</em>, <em>Green</em>, <em>Blue</em>)
<em>ENUM</em>(<em>Channel</em>, <em>int</em>, <em>Red</em> = <em>1</em>, <em>Green</em>, <em>Blue</em>)
you don't get names such as `Red` in the global namespace. Instead, you get
`Channel`, and `Red` is accessible as `Channel::Red`. This is no big deal in
@ -26,7 +20,7 @@ $cxx11, which has `enum class`. In $cxx98, however, this typically requires
effort. Better Enums brings scope uniformly to both variants. So, despite the
above declaration, you can safely declare
<em>BETTER_ENUM</em>(<em>Node</em>, <em>char</em>, <em>Red</em>, <em>Black</em>)
<em>ENUM</em>(<em>Node</em>, <em>char</em>, <em>Red</em>, <em>Black</em>)
and everything will work as expected.
@ -53,27 +47,33 @@ will not compile:
The reason this is not enabled by default is explained in the reference page on
[strict conversions](${prefix}OptInFeatures.html#StrictConversions).
You can conveniently define the macro on your compiler's command line, or by
creating a little header file that defines it, and then includes
<code>enum.h</code>. You can then include this new header file in your project
everywhere where you would have included <code>enum.h</code>.
### Default constructor
Better Enums generate without a default constructor. The purpose is to support
the convention where if a Better Enum exists, then it has a valid value. So, if
you uncomment this code, the program won't compile:
Better Enums don't have a default constructor, for three reasons.
- Better Enums is a library that can't know what your application would like
the default value to be for each enum, or whether you even want one.
- I chose not to leave the default value undefined, because the idea is to
encourage the convention that whenever a Better Enum exists, it has a valid
value. This is borrowed from typed functional programming.
- Better Enums is still under development, and this option is the most
future-proof.
So, if you uncomment this code, the file won't compile:
~~~comment
Channel channel;
~~~
If this is too strict for your project, you can relax it as described
[here](${prefix}OptInFeatures.html#DefaultConstructors).
This may be too strict, and I may relax it in the future. In the meantime, the
solution sketched in the [special values demo](${prefix}demo/SpecialValues.html)
can replace default constructors for some purposes, and in a more flexible way.
I may eventually have the default constructor calling a template function like
the one in that demo.
---
return 0;
}
%% description = Better Enums type safety features and limitations.
%% description = Type safety features and limitations.

View File

@ -1,34 +0,0 @@
## Stream operators
These work *almost* as you'd expect. First, make sure you include `iostream`
before `enum.h` in any translation unit in which you intend to use the
operators:
#include <iostream>
#include <enum.h>
<em>BETTER_ENUM(Channel, int, Red, Green, Blue)</em>
int main()
{
std::cout << <em>+Channel::Red</em> << std::endl;
return 0;
}
The thing to watch for is the `+`: without it, `Channel::Red` is a value of type
`Channel::_enumerated`, a $cxx98 enum type, so writing that to `cout` will
output an integer. `+Channel::Red`, however, is a value of type `Channel`, and
writing *that* instead will output the string `"Red"`.
Input is also supported:
~~~comment
Channel channel = Channel::Blue;
std::cin >> channel; // Expects input such as "Green".
~~~
---
Only `char` streams are supported for the time being.
%% description = Using Better Enums with stream input and output operators.

View File

@ -7,7 +7,7 @@ will declare a more unusual enum than the ones we have seen.
#include <iostream>
<em>#include <enum.h></em>
<em>BETTER_ENUM</em>(<em>ContentType</em>, <em>short</em>,
<em>ENUM</em>(<em>ContentType</em>, <em>short</em>,
<em>CompressedVideo</em> = <em>5</em>, <em>PCM</em> = <em>8</em>, <em>Subtitles</em> = <em>17</em>, <em>Comment</em> = <em>44</em>)
This is for a hypothetical multimedia container file format. Perhaps the files
@ -80,5 +80,4 @@ types containg enums. The enums will behave as expected.
compatible with $cxx98, where those names aren't available in a portable
manner.
%% description = The underlying memory representation of a Better Enum,
including size and alignment.
%% description = Underlying representation.

View File

@ -15,7 +15,7 @@ get an idea of what can be done. Here, you will see the basics.
<em>#include <enum.h></em>
<em>BETTER_ENUM</em>(<em>Channel</em>, <em>int</em>, <em>Red</em> = <em>1</em>, <em>Green</em> = <em>2</em>, <em>Blue</em> = <em>3</em>)
<em>ENUM</em>(<em>Channel</em>, <em>int</em>, <em>Red</em> = <em>1</em>, <em>Green</em> = <em>2</em>, <em>Blue</em> = <em>3</em>)
<em>constexpr</em> Channel channel = <em>Channel::_from_integral(2)</em>;
<em>constexpr</em> int value = <em>channel._to_integral()</em>;
@ -48,5 +48,4 @@ You can also do things such as:
Which prints "5", the length of "Green". That 5 was also computed during
compilation.
%% description = Better Enums can be used entirely at compile time in C++11. All
conversion functions are available for constexpr functions or templates.
%% description = Introduction to compile-time conversions.

1372
enum.h

File diff suppressed because it is too large Load Diff

View File

@ -2,12 +2,12 @@
// Hello, World!
//
// Download enum.h, then compile this program:
// Download enum.h, then build this program with it:
#include <iostream>
#include "enum.h"
BETTER_ENUM(Word, int, Hello, World)
ENUM(Word, int, Hello, World)
int main()
{

View File

@ -44,10 +44,10 @@ constexpr Enum invalid_impl<Enum>() { return Enum::Value; }
// Now, we can declare enums like these:
BETTER_ENUM(Channel, int, Red, Green, Blue, Invalid)
ENUM(Channel, int, Red, Green, Blue, Invalid)
// Invalid is the invalid value by default
BETTER_ENUM(Compression, int, Undefined, None, Huffman)
ENUM(Compression, int, Undefined, None, Huffman)
OVERRIDE_INVALID(Compression, Undefined)
// and use them:
@ -69,7 +69,7 @@ template <typename Enum>
constexpr Enum default_impl()
{
return
Enum::_size() < 2 ?
Enum::_size < 2 ?
throw std::logic_error("enum has no valid constants") :
Enum::_values()[0] == invalid_impl<Enum>() ?
Enum::_values()[1] :
@ -98,7 +98,7 @@ static_assert(default_impl<Compression>() == +Compression::None, "");
// And, if you do
BETTER_ENUM(Answer, int, Yes, No, Invalid)
ENUM(Answer, int, Yes, No, Invalid)
// OVERRIDE_DEFAULT(Answer, Invalid)
// you will get a helpful compile-time error saying Answer: default cannot equal

View File

@ -17,7 +17,7 @@ template <typename Enum>
constexpr Enum max_loop(Enum accumulator, size_t index)
{
return
index >= Enum::_size() ? accumulator :
index >= Enum::_size ? accumulator :
Enum::_values()[index] > accumulator ?
max_loop<Enum>(Enum::_values()[index], index + 1) :
max_loop<Enum>(accumulator, index + 1);
@ -38,7 +38,7 @@ using EnumSet = std::bitset<max<Enum>()._to_integral() + 1>;
// declared. We just declare enums, and the numeric values of their constants
// will be bit indices. The rest is straightforward.
BETTER_ENUM(EFLAGS, int,
ENUM(EFLAGS, int,
Carry, Parity = 2, Adjust = 4, Zero, Sign, Trap, Interrupt, Direction,
Overflow, NestedTask = 14, Resume = 16, V8086, AlignmentCheck,
CPUIDPresent = 21)

View File

@ -10,7 +10,7 @@
// Ok, so it's not really a quine, because we won't be writing all the code
// needed to generate the definition to the buffer as well. And, there are
// better ways to dump the definition than shown here. You could simply define a
// macro that expands to an BETTER_ENUM declaration and also stringizes it.
// macro that expands to an ENUM declaration and also stringizes it.
//
// But that's not the point here. The point of this page is to show some of the
// reflective capabilities of Better Enums, so you can adapt them for cases
@ -34,8 +34,8 @@
// Now, let's declare some enums to dump later:
BETTER_ENUM(Channel, int, Red, Green, Blue)
BETTER_ENUM(Depth, int, TrueColor = 1, HighColor = 0)
ENUM(Channel, int, Red, Green, Blue)
ENUM(Depth, int, TrueColor = 1, HighColor = 0)
@ -79,7 +79,7 @@ template <typename Enum>
constexpr size_t constants_length(size_t index = 0, size_t accumulator = 0)
{
return
index >= Enum::_size() ? accumulator :
index >= Enum::_size ? accumulator :
constants_length<Enum>(
index + 1, accumulator
+ string_length(", ")
@ -99,7 +99,7 @@ template <typename Enum>
constexpr size_t declaration_length()
{
return
string_length("BETTER_ENUM(")
string_length("ENUM(")
+ string_length(Enum::_name())
+ string_length(", int")
+ constants_length<Enum>()
@ -127,7 +127,7 @@ size_t format(char *buffer)
{
size_t offset = 0;
offset += std::sprintf(buffer, "BETTER_ENUM(%s, int", Enum::_name());
offset += std::sprintf(buffer, "ENUM(%s, int", Enum::_name());
for (Enum value : Enum::_values()) {
offset +=
@ -163,5 +163,5 @@ int main()
// It prints:
//
// BETTER_ENUM(Channel, int, Red = 0, Green = 1, Blue = 2)
// BETTER_ENUM(Depth, int, TrueColor = 1, HighColor = 0)
// ENUM(Channel, int, Red = 0, Green = 1, Blue = 2)
// ENUM(Depth, int, TrueColor = 1, HighColor = 0)

View File

@ -1,152 +0,0 @@
// This file was generated automatically.
// C++17 reflection proposal
//
// You can try this demo live online.
//
// Better Enums can be used to implement the enums portion of the C++17
// reflection proposal N4428 in C++11. N4428 proposes the following traits
// interface:
//
// namespace std {
//
// template <typename E>
// struct enum_traits {
// struct enumerators {
// constexpr static size_t size;
//
// template <size_t I>
// struct get {
// constexpr string_literal identifier;
// constexpr static E value;
// };
// };
// };
//
// }
//
// So, the basic usage would be:
//
// enum class Foo {A, B, C};
//
// constexpr size_t size =
// std::enum_traits<Foo>::enumerators::size;
//
// constexpr Foo value_0 =
// std::enum_traits<Foo>::enumerators::get<0>::value;
//
// constexpr string_literal name_1 =
// std::enum_traits<Foo>::enumerators::get<1>::identifier;
//
// Resulting in the values 3, Foo::A, and "B", respectively.
// The interface is implemented in the optional header file
// extra/better-enums/n4428.h. There is a necessary difference: the interface is
// only available for enums declared through the BETTER_ENUM macro. This is
// because the macro is what generates the information necessary for reflection.
//
// Demo
//
// So, with that out of the way, we can do a little test. Let's assume that
// extra/ has been added as a directory to search for include files.
#ifndef BETTER_ENUMS_CONSTEXPR_TO_STRING
#define BETTER_ENUMS_CONSTEXPR_TO_STRING
#endif
#include <iostream>
#include <enum.h>
#include <better-enums/n4428.h>
// Let's declare an enum:
BETTER_ENUM(Channel, char, Red = 1, Green, Blue)
// ...and try N4428:
constexpr std::size_t size =
std::enum_traits<Channel>::enumerators::size;
constexpr Channel value_0 =
std::enum_traits<Channel>::enumerators::get<0>::value;
constexpr Channel value_1 =
std::enum_traits<Channel>::enumerators::get<1>::value;
constexpr const char *identifier_2 =
std::enum_traits<Channel>::enumerators::get<2>::identifier;
// ...and check the results:
static_assert(size == 3, "");
static_assert(value_0 == +Channel::Red, "");
static_assert(value_1 == +Channel::Green, "");
int main()
{
std::cout << identifier_2 << std::endl;
return 0;
}
// That prints Blue, as you would expect.
//
// Quirk
//
// The reason for the #define in the code above is that there is one quirk: the
// interface above is available only for Better Enums for which compile-time
// name trimming is enabled - those declared when
// BETTER_ENUMS_CONSTEXPR_TO_STRING was defined, or declared with the SLOW_ENUM
// variant of BETTER_ENUM. As mentioned on the linked page, the reason
// compile-time name trimming is not the default is that, while still pretty
// fast, it is four times slower than program-startup-time name trimming. The
// latter is the default.
//
// Despite the above, a variation on the interface is available for enums
// without compile-time name trimming:
//
// namespace std {
//
// template <typename E>
// struct enum_traits {
// struct enumerators {
// constexpr static size_t size;
//
// template <size_t I>
// struct get {
// constexpr const char *identifier;
// constexpr static E value;
// };
//
// // For enums without compile-time name trimming.
// template <size_t I>
// struct get_alt {
// static const char* identifier();
// constexpr static E value;
// };
// };
// };
//
// }
//
// As you can see, the difference is that identifier is a non-constexpr
// function, and you have to access it through get_alt<I>.
//
// // Without compile-time name trimming.
// BETTER_ENUM(Depth, int, HighColor, TrueColor)
//
// int main()
// {
// std::cout
// << std::enum_traits<Depth>::enumerators::get_alt<1>::identifier()
// << std::endl;
//
// return 0;
// }
//
// The future
//
// N4428 is the fourth in a series of revisions: N3815, N4027, N4113, N4428. If
// there are more revisions that change the proposal for enums, I will try to
// implement those as well.

View File

@ -9,7 +9,7 @@
#include <enum.h>
BETTER_ENUM(Channel, int, Cyan = 1, Magenta, Yellow, Black)
ENUM(Channel, int, Cyan = 1, Magenta, Yellow, Black)
// We now have an int-sized enum with four constants.
//

View File

@ -8,12 +8,12 @@
#include <iostream>
#include <enum.h>
BETTER_ENUM(Channel, int, Red, Green = 2, Blue)
ENUM(Channel, int, Red, Green = 2, Blue)
int main()
{
for (size_t index = 0; index < Channel::_size(); ++index) {
for (size_t index = 0; index < Channel::_size; ++index) {
Channel channel = Channel::_values()[index];
std::cout << channel._to_integral() << " ";
}
@ -21,7 +21,7 @@ int main()
// will print "0 2 3". And this:
for (size_t index = 0; index < Channel::_size(); ++index) {
for (size_t index = 0; index < Channel::_size; ++index) {
const char *name = Channel::_names()[index];
std::cout << name << " ";
}

View File

@ -7,7 +7,7 @@
#include <iostream>
#include <enum.h>
BETTER_ENUM(Channel, int, Red, Green, Blue)
ENUM(Channel, int, Red, Green, Blue)
int main()
{
@ -22,8 +22,6 @@ int main()
// If you miss a case or add a redundant one, your compiler should be able to
// give you a warning - try it!
//
// Note that on msvc, you may need to enable warning C4062.
std::cout << n << std::endl;

View File

@ -1,74 +0,0 @@
// This file was generated automatically.
// Maps
//
// It is possible to create constexpr bidirectional maps between Better Enums
// and any type. This is currently an experimental feature. Feedback is very
// much wanted, but please don't build any mission-critical code on top of this
// :)
//
// The way it works is you give Better Enums a function - say, const char*
// describe(Channel). The library enumerates it to make a map.
//
// The reason for using a function is that a switch statement is, I believe, the
// only place where a compiler will check for exhaustiveness. If you forget to
// create a case for one of the enum's constants, the compiler can let you know.
// Obviously, a switch statement is not data, and needs to be inside a function.
// It can only be inside a constexpr function in C++14, so this feature is most
// natural in C++14. When you pass the function to Better Enums, the library can
// build up a lookup data structure at compile time.
//
// Actually, right now, Better Enums doesn't quite do that - it enumerates the
// function every time you want to convert to an enum (but not from an enum). It
// simply does a linear scan every time. This is because I haven't yet found a
// data structure whose compile-time generation is fast enough for practical
// use.
#include <iostream>
#include <enum.h>
BETTER_ENUM(Channel, int, Red, Green, Blue)
// We will create a map from this function:
constexpr const char* describe(Channel channel)
{
switch(channel) {
case Channel::Red: return "the red channel";
case Channel::Green: return "the green channel";
case Channel::Blue: return "the blue channel";
}
return "needed for gcc 5";
}
// Here is the map. The actual type is better_enums::map<Channel, const char*>.
constexpr auto descriptions = better_enums::make_map(describe);
// And the usage:
int main()
{
std::cout << descriptions[Channel::Red] << std::endl;
std::cout << descriptions.from_enum(Channel::Red) << std::endl;
std::cout << descriptions.to_enum("the green channel") << std::endl;
auto not_a_literal = std::string("the blue channel");
std::cout << descriptions.to_enum(not_a_literal.c_str()) << std::endl;
return 0;
}
// make_map above produces a value of type better_enums::map<E, T>. The full
// signature of the template better_enums::map is
//
// template <typename Enum, typename T, typename Compare = map_compare<T>>
//
// Compare has to be a class with a static member function bool less(const T&,
// const T&). The default implementation better_enums::map_compare simply
// applies operator <, except when T is const char*. In that case, it does
// lexicographic comparison.

View File

@ -5,12 +5,6 @@
// This tutorial shows some of the safety features of Better Enums: scope, how
// to control conversions, and the lack of a default constructor.
//
// On balance, Better Enums are in one way less type-safe than enum class, and
// in another way more type-safe. The first difference in safety is the presence
// of implicit conversion to integral types. The second difference is the lack
// of a default constructor. Both of these can be toggled, so you can make
// Better Enums strictly safer than enum class, or just as safe.
//
// Scope
//
// You have probably noticed by now that Better Enums are scoped: when you
@ -19,7 +13,7 @@
#include <cassert>
#include <enum.h>
BETTER_ENUM(Channel, int, Red = 1, Green, Blue)
ENUM(Channel, int, Red = 1, Green, Blue)
// you don't get names such as Red in the global namespace. Instead, you get
// Channel, and Red is accessible as Channel::Red. This is no big deal in C++11,
@ -27,7 +21,7 @@ BETTER_ENUM(Channel, int, Red = 1, Green, Blue)
// Better Enums brings scope uniformly to both variants. So, despite the above
// declaration, you can safely declare
BETTER_ENUM(Node, char, Red, Black)
ENUM(Node, char, Red, Black)
// and everything will work as expected.
@ -51,20 +45,28 @@ int main()
// The reason this is not enabled by default is explained in the reference page
// on strict conversions.
//
// You can conveniently define the macro on your compiler's command line, or by
// creating a little header file that defines it, and then includes enum.h. You
// can then include this new header file in your project everywhere where you
// would have included enum.h.
//
// Default constructor
//
// Better Enums generate without a default constructor. The purpose is to
// support the convention where if a Better Enum exists, then it has a valid
// value. So, if you uncomment this code, the program won't compile:
// Better Enums don't have a default constructor, for three reasons.
//
// 1. Better Enums is a library that can't know what your application would
// like the default value to be for each enum, or whether you even want
// one.
// 2. I chose not to leave the default value undefined, because the idea is to
// encourage the convention that whenever a Better Enum exists, it has a
// valid value. This is borrowed from typed functional programming.
// 3. Better Enums is still under development, and this option is the most
// future-proof.
//
// So, if you uncomment this code, the file won't compile:
//
// Channel channel;
//
// If this is too strict for your project, you can relax it as described here.
// This may be too strict, and I may relax it in the future. In the meantime,
// the solution sketched in the special values demo can replace default
// constructors for some purposes, and in a more flexible way. I may eventually
// have the default constructor calling a template function like the one in that
// demo.
return 0;

View File

@ -1,30 +0,0 @@
// This file was generated automatically.
// Stream operators
//
// These work almost as you'd expect. First, make sure you include iostream
// before enum.h in any translation unit in which you intend to use the
// operators:
#include <iostream>
#include <enum.h>
BETTER_ENUM(Channel, int, Red, Green, Blue)
int main()
{
std::cout << +Channel::Red << std::endl;
return 0;
}
// The thing to watch for is the +: without it, Channel::Red is a value of type
// Channel::_enumerated, a C++98 enum type, so writing that to cout will output
// an integer. +Channel::Red, however, is a value of type Channel, and writing
// that instead will output the string "Red".
//
// Input is also supported:
//
// Channel channel = Channel::Blue;
// std::cin >> channel; // Expects input such as "Green".
// Only char streams are supported for the time being.

View File

@ -9,7 +9,7 @@
#include <iostream>
#include <enum.h>
BETTER_ENUM(ContentType, short,
ENUM(ContentType, short,
CompressedVideo = 5, PCM = 8, Subtitles = 17, Comment = 44)
// This is for a hypothetical multimedia container file format. Perhaps the

View File

@ -17,7 +17,7 @@
#include <enum.h>
BETTER_ENUM(Channel, int, Red = 1, Green = 2, Blue = 3)
ENUM(Channel, int, Red = 1, Green = 2, Blue = 3)
constexpr Channel channel = Channel::_from_integral(2);
constexpr int value = channel._to_integral();

View File

@ -3,7 +3,7 @@ CXX := c++
endif
ifndef CXXFLAGS
CXXFLAGS := -std=c++11 -Wall -I .. -I../extra -o
CXXFLAGS := -std=c++11 -Wall -I .. -o
endif
SOURCES := $(wildcard *.cc)

View File

@ -1,52 +0,0 @@
// This file is part of Better Enums, released under the BSD 2-clause license.
// See doc/LICENSE for details, or visit http://github.com/aantron/better-enums.
// This file provides an implementation of the enum reflection interface
// proposed in
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4428.pdf
// on top of Better Enums.
// See further discussion and a demonstration of usage at
// example/107-c++17-reflection.cc, or visit:
// http://aantron.github.io/better-enums/demo/C++17ReflectionProposal.html
#pragma once
#ifndef BETTER_ENUMS_N4428_H
#define BETTER_ENUMS_N4428_H
namespace std {
template <typename Enum>
struct enum_traits {
struct enumerators {
constexpr static const size_t size = Enum::_size();
template <size_t Index>
struct get {
constexpr static Enum value = Enum::_values()[Index];
constexpr static const char *identifier = Enum::_names()[Index];
};
// The above declarations implement N4428 (except for const char*
// instead of string_literal). The alternative get below is needed for
// Better Enums that weren't generated with compile-time name trimming,
// i.e. without BETTER_ENUMS_CONSTEXPR_TO_STRING declared and not
// through the SLOW_ENUM macro. That is currently the default for
// Better Enums, since compile-time name trimming is pretty slow, so you
// would want to use get_alt instead of get.
template <size_t Index>
struct get_alt {
constexpr static Enum value = Enum::_values()[Index];
static const char* identifier() { return Enum::_names()[Index]; };
};
};
};
}
#endif // #ifndef BETTER_ENUMS_N4428_H

View File

@ -3,19 +3,18 @@
# This file is part of Better Enums, released under the BSD 2-clause license.
# See LICENSE for details, or visit http://github.com/aantron/better-enums.
# You only need this script if you are developing enum.h, or run into a limit.
# This script generates the macros _ENUM_PP_MAP and _ENUM_ITERATE, used
# internally by enum.h. These are already inlined into enum.h. You only need
# this script if you are developing enum.h, or run into a limit.
#
# This script generates the macros BETTER_ENUMS_PP_MAP and BETTER_ENUMS_ITERATE,
# used internally by enum.h. These are already inlined into enum.h.
# _ENUM_PP_MAP has a limit, which determines the maximum number of constants an
# enum can have. By default, this limit is 64 constants.
#
# BETTER_ENUMS_PP_MAP has a limit, which determines the maximum number of
# constants an enum can have. By default, this limit is 64 constants.
#
# BETTER_ENUMS_ITERATE also has a limit. This one determines the maximum length
# of the name of a constant that is followed by an initializer (" = 2") when
# compiling an enum with constexpr _to_string function (i.e. usually, this limit
# does not apply). By default, the limit is 23 characters (24 with the
# obligatory null terminator).
# _ENUM_ITERATE also has a limit. This one determines the maximum length of the
# name of a constant that is followed by an initializer (" = 2") when compiling
# an enum with constexpr to_string function (i.e. usually, this limit does not
# apply). By default, the limit is 23 characters (24 with the obligatory null
# terminator).
#
# If either of these limits is inadequate, you can still compile your code
# without changing enum.h. You need to generate an external macro file with
@ -29,7 +28,7 @@
# 2. Build your code with an additional compiler flag:
# - for gcc and clang, -DBETTER_ENUMS_MACRO_FILE='<MACRO_FILE>'
# - for VC++, /DBETTER_ENUMS_MACRO_FILE='<MACRO_FILE>'
# or use any other method of getting these macros defined.
# or use any other method of getting these macros declared.
# 3. Compile your code. Your macro file should be included, and enum.h should
# happily work with whatever limits you chose.
@ -67,38 +66,35 @@ def generate(stream, constants, length, script):
print >> stream, ''
print >> stream, '#pragma once'
print >> stream, ''
print >> stream, '#ifndef BETTER_ENUMS_MACRO_FILE_H'
print >> stream, '#define BETTER_ENUMS_MACRO_FILE_H'
print >> stream, '#ifndef _BETTER_ENUM_MACRO_FILE_H_'
print >> stream, '#define _BETTER_ENUM_MACRO_FILE_H_'
print >> stream, ''
print >> stream, '#define BETTER_ENUMS_PP_MAP(macro, data, ...) \\'
print >> stream, ' BETTER_ENUMS_ID( \\'
print >> stream, ' BETTER_ENUMS_APPLY( \\'
print >> stream, ' BETTER_ENUMS_PP_MAP_VAR_COUNT, \\'
print >> stream, ' BETTER_ENUMS_PP_COUNT(__VA_ARGS__)) \\'
print >> stream, '#define _ENUM_PP_MAP(macro, data, ...) \\'
print >> stream, ' _ENUM_ID(_ENUM_A(_ENUM_PP_MAP_VAR_COUNT, ' + \
'_ENUM_PP_COUNT(__VA_ARGS__)) \\'
print >> stream, ' (macro, data, __VA_ARGS__))'
print >> stream, ''
print >> stream, '#define BETTER_ENUMS_PP_MAP_VAR_COUNT(count) ' + \
'BETTER_ENUMS_M ## count'
print >> stream, '#define _ENUM_PP_MAP_VAR_COUNT(count) ' + \
'_ENUM_M ## count'
print >> stream, ''
print >> stream, '#define BETTER_ENUMS_APPLY(macro, ...) ' + \
'BETTER_ENUMS_ID(macro(__VA_ARGS__))'
print >> stream, '#define _ENUM_A(macro, ...) _ENUM_ID(macro(__VA_ARGS__))'
print >> stream, ''
print >> stream, '#define BETTER_ENUMS_ID(x) x'
print >> stream, '#define _ENUM_ID(x) x'
print >> stream, ''
print >> stream, '#define BETTER_ENUMS_M1(m, d, x) m(d,0,x)'
print >> stream, '#define _ENUM_M1(m, d, x) m(d,0,x)'
for index in range(2, constants + 1):
print >> stream, '#define BETTER_ENUMS_M' + str(index) + \
'(m,d,x,...) m(d,' + str(index - 1) + ',x) \\'
print >> stream, ' BETTER_ENUMS_ID(BETTER_ENUMS_M' + \
str(index - 1) + '(m,d,__VA_ARGS__))'
print >> stream, '#define _ENUM_M' + str(index) + \
'(m,d,x,...) m(d,' + str(index - 1) + \
',x) _ENUM_ID(_ENUM_M' + str(index - 1) + \
'(m,d,__VA_ARGS__))'
print >> stream, ''
pp_count_impl_prefix = '#define BETTER_ENUMS_PP_COUNT_IMPL(_1,'
pp_count_impl_prefix = '#define _ENUM_PP_COUNT_IMPL(_1,'
stream.write(pp_count_impl_prefix)
pp_count_impl = MultiLine(stream = stream, indent = 4,
initial_column = len(pp_count_impl_prefix))
@ -110,11 +106,10 @@ def generate(stream, constants, length, script):
print >> stream, ''
print >> stream, ''
print >> stream, '#define BETTER_ENUMS_PP_COUNT(...) \\'
pp_count_prefix = \
' BETTER_ENUMS_ID(BETTER_ENUMS_PP_COUNT_IMPL(__VA_ARGS__,'
'#define _ENUM_PP_COUNT(...) _ENUM_ID(_ENUM_PP_COUNT_IMPL(__VA_ARGS__,'
stream.write(pp_count_prefix)
pp_count = MultiLine(stream = stream, indent = 8,
pp_count = MultiLine(stream = stream, indent = 4,
initial_column = len(pp_count_prefix))
for index in range(0, constants - 1):
pp_count.write(' ' + str(constants - index) + ',')
@ -122,7 +117,7 @@ def generate(stream, constants, length, script):
print >> stream, ''
print >> stream, ''
iterate_prefix = '#define BETTER_ENUMS_ITERATE(X, f, l)'
iterate_prefix = '#define _ENUM_ITERATE(X, f, l)'
stream.write(iterate_prefix)
iterate = MultiLine(stream = stream, indent = 4,
initial_column = len(iterate_prefix))
@ -131,7 +126,7 @@ def generate(stream, constants, length, script):
print >> stream, ''
print >> stream, ''
print >> stream, '#endif // #ifndef BETTER_ENUMS_MACRO_FILE_H'
print >> stream, '#endif // #ifndef _BETTER_ENUM_MACRO_FILE_H_'
if __name__ == '__main__':
if len(sys.argv) != 3:

View File

@ -1,203 +0,0 @@
# Invoked automatically by the Makefile.
cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR)
project("Better Enums Testing" CXX)
# Detect compiler feature support.
list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_constexpr CONSTEXPR_INDEX)
if(CONSTEXPR_INDEX EQUAL -1)
set(SUPPORTS_CONSTEXPR 0)
else()
set(SUPPORTS_CONSTEXPR 1)
endif()
list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_relaxed_constexpr
RELAXED_CONSTEXPR_INDEX)
if(RELAXED_CONSTEXPR_INDEX EQUAL -1)
set(SUPPORTS_RELAXED_CONSTEXPR 0)
else()
set(SUPPORTS_RELAXED_CONSTEXPR 1)
endif()
# Current versions of CMake report VS2015 as supporting constexpr. However, the
# support is too buggy to build Better Enums. Avoid trying to build constexpr
# configurations on MSVC.
if(${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC)
set(SUPPORTS_CONSTEXPR 0)
set(SUPPORTS_RELAXED_CONSTEXPR 0)
endif()
list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_strong_enums ENUM_CLASS_INDEX)
if(ENUM_CLASS_INDEX EQUAL -1)
set(SUPPORTS_ENUM_CLASS 0)
else()
set(SUPPORTS_ENUM_CLASS 1)
endif()
# Not supporting C++11 usage on g++46 due to buggy constexpr.
if(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7)
set(SUPPORTS_CONSTEXPR 0)
set(SUPPORTS_ENUM_CLASS 0)
endif()
# Not supporting C++14 testing on clang++34 due to buggy library installed in
# Travis Ubuntu image.
if(CMAKE_CXX_COMPILER_ID STREQUAL Clang
AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.5)
set(SUPPORTS_RELAXED_CONSTEXPR 0)
endif()
# Select standard based on the requested configuration. If the compiler does not
# support the requested configuration, write a message and generate a no-op
# build. This condition is not a failure.
#
# If no configuration is explicitly requested, default to compiling with no
# special flags, with the latest standard supported by the compiler.
set(DO_NOT_TEST_FILE "${CMAKE_BINARY_DIR}/do-not-test")
if(CONFIGURATION STREQUAL CONSTEXPR)
if(SUPPORTS_CONSTEXPR)
set(CMAKE_CXX_STANDARD 11)
else()
message(WARNING "This compiler does not support constexpr")
file(WRITE "${DO_NOT_TEST_FILE}")
return()
endif()
elseif(CONFIGURATION STREQUAL FULL_CONSTEXPR)
if(SUPPORTS_CONSTEXPR)
set(CMAKE_CXX_STANDARD 11)
add_definitions(-DBETTER_ENUMS_CONSTEXPR_TO_STRING)
else()
message(WARNING "This compiler does not support constexpr")
file(WRITE "${DO_NOT_TEST_FILE}")
return()
endif()
elseif(CONFIGURATION STREQUAL STRICT_CONVERSION)
if(SUPPORTS_ENUM_CLASS)
set(CMAKE_CXX_STANDARD 11)
add_definitions(-DBETTER_ENUMS_STRICT_CONVERSION)
else()
message(WARNING "This compiler does not support enum class")
file(WRITE "${DO_NOT_TEST_FILE}")
return()
endif()
elseif(CONFIGURATION STREQUAL CXX98)
set(CMAKE_CXX_STANDARD 98)
elseif(CONFIGURATION STREQUAL CXX14)
if(SUPPORTS_RELAXED_CONSTEXPR)
set(CMAKE_CXX_STANDARD 14)
else()
message(WARNING "This compiler does not support relaxed constexpr")
file(WRITE "${DO_NOT_TEST_FILE}")
return()
endif()
else()
set(CMAKE_CXX_STANDARD 11)
endif()
# Basic tests.
add_executable(cxxtest cxxtest/tests.cc)
add_executable(linking linking/helper.cc linking/main.cc)
set(PERFORMANCE_TESTS
1-simple 2-include_empty 3-only_include_enum 4-declare_enums 5-iostream)
foreach(TEST ${PERFORMANCE_TESTS})
add_executable(performance-${TEST} performance/${TEST}.cc)
endforeach(TEST)
# Select examples to build.
set(EXAMPLES
1-hello-world 2-conversions 3-iterate 4-switch 6-iostreams 7-safety
8-representation 9-constexpr 101-special-values 103-bitset 104-quine
105-c++17-reflection)
set(SKIPPED_FOR_CXX98
5-map 9-constexpr 101-special-values 103-bitset 104-quine
105-c++17-reflection)
set(SKIPPED_FOR_STRICT_CONVERSION 4-switch)
if(CONFIGURATION STREQUAL CXX98 OR NOT SUPPORTS_CONSTEXPR)
list(REMOVE_ITEM EXAMPLES ${SKIPPED_FOR_CXX98})
endif()
if(CONFIGURATION STREQUAL STRICT_CONVERSION)
list(REMOVE_ITEM EXAMPLES ${SKIPPED_FOR_STRICT_CONVERSION})
endif()
if(CONFIGURATION STREQUAL CXX14)
set(EXAMPLES 5-map)
endif()
foreach(EXAMPLE ${EXAMPLES})
add_executable(example-${EXAMPLE} ../example/${EXAMPLE}.cc)
endforeach(EXAMPLE)
# Add compiler flags.
include_directories(..)
include_directories(../extra)
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES Clang)
include(CheckCXXCompilerFlag)
macro(add_cxx_flag_if_supported FLAG)
check_cxx_compiler_flag("${FLAG}" HAVE_FLAG_${FLAG})
if(HAVE_FLAG_${FLAG})
add_definitions(${FLAG})
endif()
endmacro()
macro(add_cxx_flag_to_target_if_supported TARGET FLAG)
string(REPLACE "=" "_equals_" ESCAPED ${FLAG})
string(REPLACE "+" "_plus_" ESCAPED ${ESCAPED})
check_cxx_compiler_flag("${FLAG}" HAVE_FLAG_${FLAG})
if(HAVE_FLAG_${FLAG})
get_target_property(FLAGS ${TARGET} COMPILE_FLAGS)
if(${FLAGS} STREQUAL "FLAGS-NOTFOUND")
set(FLAGS "")
endif()
set_target_properties(
${TARGET} PROPERTIES COMPILE_FLAGS "${FLAGS} ${FLAG}")
endif()
endmacro()
add_cxx_flag_if_supported("-Wpedantic")
add_cxx_flag_if_supported("-Wall")
add_cxx_flag_if_supported("-Wextra")
add_cxx_flag_if_supported("-Wno-variadic-macros")
add_cxx_flag_if_supported("-Wno-unused-const-variable")
add_cxx_flag_to_target_if_supported(linking "-Weverything")
add_cxx_flag_to_target_if_supported(linking "-Wno-c++98-compat-pedantic")
add_cxx_flag_to_target_if_supported(linking "-Wno-padded")
add_cxx_flag_to_target_if_supported(linking "-Wno-global-constructors")
add_cxx_flag_to_target_if_supported(linking "-Wno-old-style-cast")
add_cxx_flag_to_target_if_supported(linking "-Wno-missing-prototypes")
add_cxx_flag_to_target_if_supported(linking "-Wshadow")
add_cxx_flag_to_target_if_supported(linking "-Weffc++")
add_cxx_flag_to_target_if_supported(linking "-Wstrict-aliasing")
add_cxx_flag_to_target_if_supported(linking "-Wformat")
add_cxx_flag_to_target_if_supported(linking "-Wmissing-include-dirs")
add_cxx_flag_to_target_if_supported(linking "-Wsync-nand")
add_cxx_flag_to_target_if_supported(linking "-Wconditionally-supported")
add_cxx_flag_to_target_if_supported(linking "-Wconversion")
add_cxx_flag_to_target_if_supported(linking "-Wuseless-cast")
add_definitions("-Werror")
endif()

View File

@ -1,167 +1,13 @@
# Run "make" for quick builds while developing.
# Run "make default-all" before submitting a pull request.
# Run "make clean" to clean up.
# See doc/CONTRIBUTING.md for full instructions.
CXXTEST_GENERATED := cxxtest/tests.cc
UNIX_MAKE_COMMAND := make
WINDOWS_MAKE_COMMAND := "MSBuild.exe \"Better Enums Testing.sln\""
UNIX_OUTPUT_DIRECTORY := .
WINDOWS_OUTPUT_DIRECTORY := Debug
ifdef COMSPEC
WIN32 := true
endif
ifdef ComSpec
WIN32 := true
endif
ifndef WIN32
DEFAULT_MAKE_COMMAND := $(UNIX_MAKE_COMMAND)
DEFAULT_OUTPUT_DIRECTORY := $(UNIX_OUTPUT_DIRECTORY)
define PATH_FIX
@true
endef
SUFFIX :=
CXXTESTGEN := cxxtestgen
else
DEFAULT_MAKE_COMMAND := $(WINDOWS_MAKE_COMMAND)
DEFAULT_OUTPUT_DIRECTORY := $(WINDOWS_OUTPUT_DIRECTORY)
define PATH_FIX
sed 's!include "/!include "C:/cygwin/!g' $1 > $$$$ && mv $$$$ $1
endef
SUFFIX := .exe
CXXTESTGEN := python `which cxxtestgen | sed -E 's!(/cygdrive)?/c/!c:/!'`
endif
DEFAULTS := \
TITLE=default \
MAKE_COMMAND=$(DEFAULT_MAKE_COMMAND) \
OUTPUT_DIRECTORY=$(DEFAULT_OUTPUT_DIRECTORY)
# Builds one configuration with the system compiler. This will be either a
# regular C++11 or C++98 build (no constexpr to_string and no strict
# conversions).
.PHONY : default
default : examples
make $(DEFAULTS) one-configuration
# Builds all configurations with the system compiler.
.PHONY : default-all
default-all : examples
make $(DEFAULTS) all-configurations
.PHONY : examples
examples :
default :
make -C ../doc examples
python test.py
# Example: make COMPILER=clang++36 unix
.PHONY : unix
unix :
make TITLE=$(COMPILER) CMAKE_OPTIONS="-DCMAKE_CXX_COMPILER=$(COMPILER)" \
MAKE_COMMAND=$(UNIX_MAKE_COMMAND) \
OUTPUT_DIRECTORY=$(UNIX_OUTPUT_DIRECTORY) all-configurations
# Example: make TITLE=vc2013 COMPILER="Visual Studio 12 2013" ms
.PHONY : ms
ms :
make TITLE=$(TITLE) CMAKE_OPTIONS="-G \\\"$(COMPILER)\\\"" \
MAKE_COMMAND=$(WINDOWS_MAKE_COMMAND) \
OUTPUT_DIRECTORY=$(WINDOWS_OUTPUT_DIRECTORY) all-configurations
# Expects three variables to be defined:
# CMAKE_OPTIONS:
# First, the compiler:
# - Empty for a "default" build.
# - -G "Visual Studio XX YYYY" to select a specific Microsoft compiler.
# - -DCMAKE_CXX_COMPILER=AAA to select a specific Unix compiler binary.
# Configuration selection (e.g. -DCONFIGURATION=CXX98) also go here.
# TITLE:
# The build title (subdirectory). Some combination of compiler/configuration.
# MAKE_COMMAND:
# Either make or msbuild "Better Enums Testing.sln"
# OUTPUT_DIRECTORY:
# Path to generated binaries relative to build directory. Either "." or
# "Debug".
.PHONY : one-configuration
one-configuration : $(CXXTEST_GENERATED)
mkdir -p build/$(TITLE)
cd build/$(TITLE) && cmake $(CMAKE_OPTIONS) ../.. && $(MAKE_COMMAND)
rm -rf build/$(TITLE)/bin
[ -f build/$(TITLE)/do-not-test ] || \
( ln -s $(OUTPUT_DIRECTORY) build/$(TITLE)/bin && \
make BIN=build/$(TITLE)/bin run-tests )
.PHONY : run-tests
run-tests :
$(BIN)/cxxtest
@for FILE in $(BIN)/example-*$(SUFFIX) ; \
do \
EXAMPLE=$$(basename $$FILE | sed s/\.exe$$// | sed s/^example-//) ; \
$$FILE | sed 's/\r$$//' | cmp - expect/$$EXAMPLE ; \
RESULT=$$? ; \
if [ $$RESULT -ne 0 ] ; \
then \
echo \'$$FILE\' produced bad output ; \
exit $$RESULT ; \
fi ; \
done
@echo Example program output matches expected output
.PHONY : all-configurations
all-configurations :
make TITLE=$(TITLE)-c++11 \
CMAKE_OPTIONS="$(CMAKE_OPTIONS) -DCONFIGURATION=CONSTEXPR" \
one-configuration
make TITLE=$(TITLE)-full-constexpr \
CMAKE_OPTIONS="$(CMAKE_OPTIONS) -DCONFIGURATION=FULL_CONSTEXPR" \
one-configuration
make TITLE=$(TITLE)-enum-class \
CMAKE_OPTIONS="$(CMAKE_OPTIONS) -DCONFIGURATION=STRICT_CONVERSION" \
one-configuration
make TITLE=$(TITLE)-c++14 \
CMAKE_OPTIONS="$(CMAKE_OPTIONS) -DCONFIGURATION=CXX14" \
one-configuration
make TITLE=$(TITLE)-c++98 \
CMAKE_OPTIONS="$(CMAKE_OPTIONS) -DCONFIGURATION=CXX98" \
one-configuration
.PHONY : all-unix
all-unix : examples
make COMPILER=clang++39 unix
make COMPILER=clang++38 unix
make COMPILER=clang++37 unix
make COMPILER=g++52 unix
make COMPILER=g++46 unix
make COMPILER=g++47 unix
make COMPILER=g++43 unix
make COMPILER=g++48 unix
make COMPILER=g++49 unix
make COMPILER=g++44 unix
make COMPILER=g++45 unix
make COMPILER=clang++33 unix
make COMPILER=clang++34 unix
make COMPILER=clang++35 unix
make COMPILER=clang++36 unix
.PHONY : all-ms
all-ms : examples
make TITLE=vc2015 COMPILER="Visual Studio 14 2015" ms
make TITLE=vc2008 COMPILER="Visual Studio 9 2008" ms
make TITLE=vc2010 COMPILER="Visual Studio 10 2010" ms
make TITLE=vc2012 COMPILER="Visual Studio 11 2012" ms
make TITLE=vc2013 COMPILER="Visual Studio 12 2013" ms
$(CXXTEST_GENERATED) : cxxtest/*.h
$(CXXTESTGEN) --error-printer -o $@ $^
$(call PATH_FIX,$@)
.PHONY : platform
platform :
make -C ../doc examples
python test.py --all
.PHONY : clean
clean :
rm -rf build $(CXXTEST_GENERATED)
rm -rf platform *.obj

View File

@ -1,29 +0,0 @@
#include <cxxtest/TestSuite.h>
#include <iostream>
#include <enum.h>
BETTER_ENUM(Compiler, int, GCC, Clang, MSVC)
class StreamOperatorTests : public CxxTest::TestSuite {
public:
void test_output()
{
std::stringstream stream;
stream << +Compiler::GCC;
TS_ASSERT_EQUALS(strcmp(stream.str().c_str(), "GCC"), 0);
}
void test_input()
{
std::stringstream stream("Clang");
Compiler compiler = Compiler::GCC;
stream >> compiler;
TS_ASSERT_EQUALS(compiler, +Compiler::Clang);
}
};

View File

@ -1,4 +1,3 @@
#include <iosfwd>
#include <stdexcept>
#include <cxxtest/TestSuite.h>
#include <enum.h>
@ -13,28 +12,17 @@
BETTER_ENUM(Channel, short, Red, Green, Blue)
BETTER_ENUM(Depth, short, HighColor = 40, TrueColor = 20)
BETTER_ENUM(Compression, short, None, Huffman, Default = Huffman)
ENUM(Channel, short, Red, Green, Blue)
ENUM(Depth, short, HighColor = 40, TrueColor = 20)
ENUM(Compression, short, None, Huffman, Default = Huffman)
namespace test {
BETTER_ENUM(Namespaced, short, One, Two)
}
// Using BETTER_ENUMS_HAVE_CONSTEXPR_ as a proxy for C++11 support. This should
// be changed to be more precise in the future.
#ifdef BETTER_ENUMS_HAVE_CONSTEXPR_
BETTER_ENUMS_DECLARE_STD_HASH(Channel)
// Using _ENUM_HAVE_CONSTEXPR as a proxy for C++11 support. This should be
// changed to be more precise in the future.
#ifdef _ENUM_HAVE_CONSTEXPR
#include <type_traits>
#include <functional>
// Type properties.
static_assert_1(std::is_class<Channel>());
@ -48,14 +36,12 @@ static_assert_1(std::is_integral<Channel::_integral>());
static_assert_1(std::is_enum<Channel::_enumerated>());
static_assert_1((std::is_same<short, Channel::_integral>()));
// Temporarily disabled due to outdated libraries in Travis.
// static_assert_1((std::is_same<
// short, std::underlying_type<Channel::_enumerated>::type>()));
static_assert_1((std::is_same<
short, std::underlying_type<Channel::_enumerated>::type>()));
static_assert_1(!(std::is_same<int, Channel::_integral>()));
// Temporarily disabled due to outdated libraries in Travis.
// static_assert_1(!(std::is_same<
// int, std::underlying_type<Channel::_enumerated>::type>()));
static_assert_1(!(std::is_same<
int, std::underlying_type<Channel::_enumerated>::type>()));
static_assert_1(sizeof(Channel) == sizeof(short));
static_assert_1(alignof(Channel) == alignof(short));
@ -66,16 +52,13 @@ static_assert_1((std::is_same<decltype(Channel::Red), Channel::_enumerated>()));
// Supported constructors.
// Apparently, this isn't supported by Clang in Travis.
// #ifdef __clang__
// static_assert_1(std::is_trivially_copyable<Channel>());
// #endif
#ifdef __clang__
static_assert_1(std::is_trivially_copyable<Channel>());
#endif
static_assert_1((std::is_constructible<Channel, Channel::_enumerated>()));
// "Passes" by causing a compilation error.
// static_assert_1(!(std::is_constructible<Channel, Channel::_integral>()));
// "Passes" on most compilers, passes on g++47 by causing a compilation error.
// static_assert_1(!(std::is_constructible<Channel, Depth>()));
static_assert_1(!(std::is_constructible<Channel, Channel::_integral>()));
static_assert_1(!(std::is_constructible<Channel, Depth>()));
// Commented out temporarily due to GCC 4.7- bug.
// static_assert_1(!std::is_default_constructible<Channel>());
@ -123,23 +106,12 @@ static_assert_1(
static_assert_1(Channel::_is_valid("Green"));
static_assert_1(Channel::_is_valid_nocase("green"));
static_assert_1(Channel::_size() == 3);
static_assert_1(Channel::_size == 3);
static_assert_1(Channel::_values().size() == 3);
static_assert_1(*Channel::_values().begin() == +Channel::Red);
static_assert_1(*(Channel::_values().end() - 1) == +Channel::Blue);
static_assert_1(Channel::_values()[1] == +Channel::Green);
namespace name_clash_test {
struct Foo {};
std::ostream& operator<<(std::ostream&, Foo);
BETTER_ENUM(Enum, int, ONE, TWO, THREE)
static_assert_1((std::is_same<decltype(std::declval<std::ostream&>() << +Enum::ONE), std::ostream&>()));
}
#ifdef BETTER_ENUMS_CONSTEXPR_TO_STRING
constexpr bool same_string(const char *r, const char *s, size_t index = 0)
@ -164,24 +136,6 @@ static_assert_1(same_string(Depth::_names()[0], "HighColor"));
// Run-time testing.
class HashTests : public CxxTest::TestSuite {
public:
void test_same_values()
{
#ifdef _ENUM_HAVE_CONSTEXPR
TS_ASSERT_EQUALS(
std::hash<Channel>().operator()(Channel::Red),
std::hash<int>().operator()(0));
TS_ASSERT_EQUALS(
std::hash<Channel>().operator()(Channel::Green),
std::hash<int>().operator()(1));
TS_ASSERT_EQUALS(
std::hash<Channel>().operator()(Channel::Blue),
std::hash<int>().operator()(2));
#endif // #ifdef _ENUM_HAVE_CONSTEXPR
}
};
class EnumTests : public CxxTest::TestSuite {
public:
void test_constant_values()
@ -256,9 +210,9 @@ class EnumTests : public CxxTest::TestSuite {
void test_value_iterable()
{
TS_ASSERT_EQUALS(Channel::_size(), 3);
TS_ASSERT_EQUALS(Depth::_size(), 2);
TS_ASSERT_EQUALS(Channel::_values().size(), Channel::_size());
TS_ASSERT_EQUALS(Channel::_size, 3);
TS_ASSERT_EQUALS(Depth::_size, 2);
TS_ASSERT_EQUALS(Channel::_values().size(), Channel::_size);
TS_ASSERT_EQUALS(*Channel::_values().begin(), +Channel::Red);
TS_ASSERT_EQUALS(*(Channel::_values().begin() + 1), +Channel::Green);
TS_ASSERT_EQUALS(*(Channel::_values().begin() + 2), +Channel::Blue);
@ -283,7 +237,7 @@ class EnumTests : public CxxTest::TestSuite {
void test_name_iterable()
{
TS_ASSERT_EQUALS(Channel::_names().size(), Channel::_size());
TS_ASSERT_EQUALS(Channel::_names().size(), Channel::_size);
TS_ASSERT_EQUALS(strcmp(*Channel::_names().begin(), "Red"), 0);
TS_ASSERT_EQUALS(strcmp(Channel::_names()[0], "Red"), 0);
TS_ASSERT_EQUALS(strcmp(Depth::_names()[0], "HighColor"), 0);
@ -315,120 +269,4 @@ class EnumTests : public CxxTest::TestSuite {
{
TS_ASSERT_EQUALS(Compression::Default, Compression::Huffman);
}
void test_namespaced()
{
TS_ASSERT_EQUALS((+test::Namespaced::One)._to_integral(), 0);
TS_ASSERT_EQUALS(test::Namespaced::_from_integral(0),
+test::Namespaced::One);
TS_ASSERT_EQUALS(strcmp((+test::Namespaced::One)._to_string(), "One"),
0);
TS_ASSERT_EQUALS(test::Namespaced::_from_string("Two"),
+test::Namespaced::Two);
TS_ASSERT_EQUALS(test::Namespaced::_values()[0],
+test::Namespaced::One);
TS_ASSERT_EQUALS(strcmp(test::Namespaced::_names()[0], "One"), 0);
TS_ASSERT_EQUALS(*test::Namespaced::_values().begin(),
+test::Namespaced::One);
TS_ASSERT_EQUALS(strcmp(*test::Namespaced::_names().begin(), "One"), 0);
}
void test_to_index()
{
TS_ASSERT_EQUALS((+Channel::Red)._to_index(), 0);
TS_ASSERT_EQUALS((+Channel::Green)._to_index(), 1);
TS_ASSERT_EQUALS((+Channel::Blue)._to_index(), 2);
TS_ASSERT_EQUALS((+Depth::HighColor)._to_index(), 0);
TS_ASSERT_EQUALS((+Depth::TrueColor)._to_index(), 1);
TS_ASSERT_EQUALS((+Compression::None)._to_index(), 0);
TS_ASSERT_EQUALS((+Compression::Huffman)._to_index(), 1);
// TS_ASSERT_EQUALS((+Compression::Default)._to_index(), 2); // This won't pass as Compression::Huffman == Compression::Default
}
void test_from_index()
{
TS_ASSERT_EQUALS((+Channel::Red), Channel::_from_index(0));
TS_ASSERT_EQUALS((+Channel::Green), Channel::_from_index(1));
TS_ASSERT_EQUALS((+Channel::Blue), Channel::_from_index(2));
TS_ASSERT_THROWS(Channel::_from_index(42), std::runtime_error);
TS_ASSERT_EQUALS((+Depth::HighColor), Depth::_from_index(0));
TS_ASSERT_EQUALS((+Depth::TrueColor), Depth::_from_index(1));
TS_ASSERT_THROWS(Depth::_from_index(42), std::runtime_error);
TS_ASSERT_EQUALS((+Compression::None), Compression::_from_index(0));
TS_ASSERT_EQUALS((+Compression::Huffman), Compression::_from_index(1));
TS_ASSERT_EQUALS((+Compression::Default), Compression::_from_index(2));
TS_ASSERT_THROWS(Compression::_from_index(42), std::runtime_error);
}
void test_from_index_nothrow()
{
better_enums::optional<Channel> maybe_channel = Channel::_from_index_nothrow(0);
TS_ASSERT(maybe_channel);
TS_ASSERT_EQUALS(*maybe_channel, +Channel::Red);
maybe_channel = Channel::_from_index_nothrow(1);
TS_ASSERT(maybe_channel);
TS_ASSERT_EQUALS(*maybe_channel, +Channel::Green);
maybe_channel = Channel::_from_index_nothrow(2);
TS_ASSERT(maybe_channel);
TS_ASSERT_EQUALS(*maybe_channel, +Channel::Blue);
maybe_channel = Channel::_from_index_nothrow(45);
TS_ASSERT(!maybe_channel);
better_enums::optional<Depth> maybe_depth = Depth::_from_index_nothrow(0);
TS_ASSERT(maybe_depth);
TS_ASSERT_EQUALS(*maybe_depth, +Depth::HighColor);
maybe_depth = Depth::_from_index_nothrow(1);
TS_ASSERT(maybe_depth);
TS_ASSERT_EQUALS(*maybe_depth, +Depth::TrueColor);
maybe_depth = Depth::_from_index_nothrow(45);
TS_ASSERT(!maybe_depth);
better_enums::optional<Compression> maybe_compression = Compression::_from_index_nothrow(0);
TS_ASSERT(maybe_compression);
TS_ASSERT_EQUALS(*maybe_compression, +Compression::None);
maybe_compression = Compression::_from_index_nothrow(1);
TS_ASSERT(maybe_compression);
TS_ASSERT_EQUALS(*maybe_compression, +Compression::Huffman);
maybe_compression = Compression::_from_index_nothrow(2);
TS_ASSERT(maybe_compression);
TS_ASSERT_EQUALS(*maybe_compression, +Compression::Default);
maybe_compression = Compression::_from_index_nothrow(45);
TS_ASSERT(!maybe_compression);
}
void test_from_index_unchecked()
{
TS_ASSERT_EQUALS((+Channel::Red), Channel::_from_index_unchecked(0));
TS_ASSERT_EQUALS((+Channel::Green), Channel::_from_index_unchecked(1));
TS_ASSERT_EQUALS((+Channel::Blue), Channel::_from_index_unchecked(2));
TS_ASSERT_EQUALS((+Depth::HighColor), Depth::_from_index_unchecked(0));
TS_ASSERT_EQUALS((+Depth::TrueColor), Depth::_from_index_unchecked(1));
TS_ASSERT_EQUALS((+Compression::None), Compression::_from_index_unchecked(0));
TS_ASSERT_EQUALS((+Compression::Huffman), Compression::_from_index_unchecked(1));
TS_ASSERT_EQUALS((+Compression::Default), Compression::_from_index_unchecked(2));
}
};
BETTER_ENUM(InternalNameCollisions, int,
EnumClassForSwitchStatements, PutNamesInThisScopeAlso,
force_initialization, value_array, raw_names, name_storage,
name_array, initialized, the_raw_names, the_name_array)

View File

@ -1,4 +0,0 @@
Red component: c4
Green component: 74
Blue component: 51
darksalmon

2
test/expect/103-quine Normal file
View File

@ -0,0 +1,2 @@
ENUM(Channel, int, Red = 0, Green = 1, Blue = 2)
ENUM(Depth, int, TrueColor = 1, HighColor = 0)

View File

@ -1,2 +0,0 @@
BETTER_ENUM(Channel, int, Red = 0, Green = 1, Blue = 2)
BETTER_ENUM(Depth, int, TrueColor = 1, HighColor = 0)

View File

@ -1 +0,0 @@
Blue

View File

@ -1,4 +0,0 @@
the red channel
the red channel
Green
Blue

View File

@ -1 +0,0 @@
Red

View File

@ -4,5 +4,4 @@
void print(Channel channel)
{
std::cout << Channel::_name() << "::" << channel._to_string() << std::endl;
std::cout << Channel::_size() << std::endl;
}

8
test/link/helper.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef _HELPER_H_
#define _HELPER_H_
#include "shared.h"
void print(Channel channel);
#endif // #ifndef _HELPER_H_

8
test/link/shared.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef _SHARED_H_
#define _SHARED_H_
#include <enum.h>
ENUM(Channel, int, Red, Green, Blue)
#endif // #ifndef _SHARED_H_

View File

@ -1,8 +0,0 @@
#ifndef HELPER_H
#define HELPER_H
#include "shared.h"
void print(Channel channel);
#endif // #ifndef HELPER_H

View File

@ -1,8 +0,0 @@
#ifndef SHARED_H
#define SHARED_H
#include <enum.h>
BETTER_ENUM(Channel, int, Red, Green, Blue)
#endif // #ifndef SHARED_H

View File

@ -1,223 +1,219 @@
#include <enum.h>
BETTER_ENUM(Channel, int,
Red, Green, Blue, Cyan, Magenta, Yellow, Black, Hue, Saturation,
Value)
ENUM(Channel, int,
Red, Green, Blue, Cyan, Magenta, Yellow, Black, Hue, Saturation, Value)
BETTER_ENUM(Direction, int,
North, East, South, West, NorthEast, SouthEast, SouthWest,
NorthWest, NorthNorthEast, EastNorthEast, EastSouthEast,
SouthSouthEast, SouthSouthWest, WestSouthWest, WestNorthWest,
NorthNorthWest)
ENUM(Direction, int,
North, East, South, West, NorthEast, SouthEast, SouthWest, NorthWest,
NorthNorthEast, EastNorthEast, EastSouthEast, SouthSouthEast,
SouthSouthWest, WestSouthWest, WestNorthWest, NorthNorthWest)
BETTER_ENUM(ASTNode, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
ENUM(ASTNode, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
BasicType, ArrowType, VariantTypeConstant)
BETTER_ENUM(State, int,
Attacking, Defending, Searching, Pursuing, Hungry, Fleeing,
Confused, Healing, Stunned)
ENUM(State, int,
Attacking, Defending, Searching, Pursuing, Hungry, Fleeing, Confused,
Healing, Stunned)
BETTER_ENUM(APIMethod, int,
ReadPost, WritePost, PollPost, ReadImage, WriteImage, PollImage,
ReadKey, WriteKey, PollKey, ReadUser, WriteUser, PollUser,
ReadOrganization, WriteOrganization, PollOrganization, ReadGroup,
WriteGroup, PollGroup, ReadProject, WriteProject, PollProject,
ReadComment, WriteComment, PollComment, ReadPermission,
WritePermission, PollPermission, ReadOwner, WriteOwner, PollOwner,
ReadProposal, WriteProposal, PollProposal, ReadHistory,
WriteHistory, PollHistory)
ENUM(APIMethod, int,
ReadPost, WritePost, PollPost, ReadImage, WriteImage, PollImage, ReadKey,
WriteKey, PollKey, ReadUser, WriteUser, PollUser, ReadOrganization,
WriteOrganization, PollOrganization, ReadGroup, WriteGroup, PollGroup,
ReadProject, WriteProject, PollProject, ReadComment, WriteComment,
PollComment, ReadPermission, WritePermission, PollPermission, ReadOwner,
WriteOwner, PollOwner, ReadProposal, WriteProposal, PollProposal,
ReadHistory, WriteHistory, PollHistory)
BETTER_ENUM(Lipsum, int,
Lorem, ipsum, dolor, sit, amet, consectetur, adipiscing, elit,
Vivamus, libero, massa, tincidunt, at, ex, nec, porta, malesuada,
arcu, Nullam, lectus, nibh, dictum, eget, convallis, ac, feugiat,
felis, Suspendisse, quis, purus, vel, lacus, cursus, tristique,
Donec, augue, tortor, luctus, a, sed, mattis, in, quam, Cras, vitae,
euismod, Cum, sociis, natoque, penatibus, et, magnis, dis,
parturient)
ENUM(Lipsum, int,
Lorem, ipsum, dolor, sit, amet, consectetur, adipiscing, elit, Vivamus,
libero, massa, tincidunt, at, ex, nec, porta, malesuada, arcu, Nullam,
lectus, nibh, dictum, eget, convallis, ac, feugiat, felis, Suspendisse,
quis, purus, vel, lacus, cursus, tristique, Donec, augue, tortor, luctus,
a, sed, mattis, in, quam, Cras, vitae, euismod, Cum, sociis, natoque,
penatibus, et, magnis, dis, parturient)
BETTER_ENUM(ASTNode0, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
ENUM(ASTNode0, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
BasicType, ArrowType, VariantTypeConstant)
BETTER_ENUM(ASTNode1, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
ENUM(ASTNode1, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
BasicType, ArrowType, VariantTypeConstant)
BETTER_ENUM(ASTNode2, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
ENUM(ASTNode2, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
BasicType, ArrowType, VariantTypeConstant)
BETTER_ENUM(ASTNode3, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
ENUM(ASTNode3, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
BasicType, ArrowType, VariantTypeConstant)
BETTER_ENUM(ASTNode4, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
ENUM(ASTNode4, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
BasicType, ArrowType, VariantTypeConstant)
BETTER_ENUM(ASTNode5, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
ENUM(ASTNode5, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
BasicType, ArrowType, VariantTypeConstant)
BETTER_ENUM(ASTNode6, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
ENUM(ASTNode6, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
BasicType, ArrowType, VariantTypeConstant)
BETTER_ENUM(ASTNode7, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
ENUM(ASTNode7, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
BasicType, ArrowType, VariantTypeConstant)
BETTER_ENUM(ASTNode8, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
ENUM(ASTNode8, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
BasicType, ArrowType, VariantTypeConstant)
BETTER_ENUM(ASTNode9, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
ENUM(ASTNode9, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
BasicType, ArrowType, VariantTypeConstant)
BETTER_ENUM(ASTNode10, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
ENUM(ASTNode10, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
BasicType, ArrowType, VariantTypeConstant)
BETTER_ENUM(ASTNode11, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
ENUM(ASTNode11, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
BasicType, ArrowType, VariantTypeConstant)
BETTER_ENUM(ASTNode12, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
ENUM(ASTNode12, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
BasicType, ArrowType, VariantTypeConstant)
BETTER_ENUM(ASTNode13, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
ENUM(ASTNode13, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
BasicType, ArrowType, VariantTypeConstant)
BETTER_ENUM(ASTNode14, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
ENUM(ASTNode14, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
BasicType, ArrowType, VariantTypeConstant)
BETTER_ENUM(ASTNode15, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
ENUM(ASTNode15, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
BasicType, ArrowType, VariantTypeConstant)
BETTER_ENUM(ASTNode16, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
ENUM(ASTNode16, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
BasicType, ArrowType, VariantTypeConstant)
BETTER_ENUM(ASTNode17, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
ENUM(ASTNode17, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
BasicType, ArrowType, VariantTypeConstant)
BETTER_ENUM(ASTNode18, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
ENUM(ASTNode18, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
BasicType, ArrowType, VariantTypeConstant)
BETTER_ENUM(ASTNode19, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
ENUM(ASTNode19, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
BasicType, ArrowType, VariantTypeConstant)
BETTER_ENUM(ASTNode20, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
ENUM(ASTNode20, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
BasicType, ArrowType, VariantTypeConstant)
BETTER_ENUM(ASTNode21, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
ENUM(ASTNode21, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
BasicType, ArrowType, VariantTypeConstant)
BETTER_ENUM(ASTNode22, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
ENUM(ASTNode22, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
BasicType, ArrowType, VariantTypeConstant)
BETTER_ENUM(ASTNode23, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
ENUM(ASTNode23, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
BasicType, ArrowType, VariantTypeConstant)
BETTER_ENUM(ASTNode24, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
ENUM(ASTNode24, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
BasicType, ArrowType, VariantTypeConstant)
BETTER_ENUM(ASTNode25, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
ENUM(ASTNode25, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
BasicType, ArrowType, VariantTypeConstant)
BETTER_ENUM(ASTNode26, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
ENUM(ASTNode26, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
BasicType, ArrowType, VariantTypeConstant)
BETTER_ENUM(ASTNode27, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
ENUM(ASTNode27, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
BasicType, ArrowType, VariantTypeConstant)
BETTER_ENUM(ASTNode28, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
ENUM(ASTNode28, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
BasicType, ArrowType, VariantTypeConstant)
BETTER_ENUM(ASTNode29, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
ENUM(ASTNode29, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
BasicType, ArrowType, VariantTypeConstant)
int main()
{

272
test/test.py Executable file
View File

@ -0,0 +1,272 @@
#! /usr/bin/env python
import glob
import os
import os.path
import platform
import re
import shutil
import subprocess
import sys
BASE_DIRECTORY = "platform"
CXXTEST_SOURCE = "cxxtest/tests.h"
CXXTEST_GENERATED = "cxxtest/tests.cc"
quiet = True
windows = False
def file_title(path):
return os.path.splitext(os.path.basename(path))[0]
expected_example_outputs = {}
def load_expected_outputs():
files = glob.glob("expect/*")
for file in files:
stream = open(file)
try:
content = stream.read()
finally:
stream.close()
expected_example_outputs[file_title(file)] = content
def run(command, catch_warnings = False):
if not quiet:
print command
try:
output = subprocess.check_output(command.split(),
stderr = subprocess.STDOUT)
if not catch_warnings:
return output
else:
if re.search("warning", output) != None:
raise subprocess.CalledProcessError(0, command, output)
return output
except subprocess.CalledProcessError as e:
print e.output
print command, "failed"
sys.exit(1)
class Configuration(object):
def __init__(self, subdirectory, command, skip_examples = []):
self._subdirectory = subdirectory
self._command = command
self._skip_examples = skip_examples
def elaborate(self, include, output, source):
command = self._command
if re.match("clang|[gc]\+\+", command) != None:
return "%s -I%s -Wall -o %s %s" % (command, include, output, source)
elif re.match("vc|cl", command) != None:
return "%s /I%s /Fe%s %s" % (command, include, output, source)
else:
raise Exception("unrecognized compiler in '%s'" % command)
def make_directories(self):
base = self.directory()
directories = \
[base,
os.path.join(base, "example"),
os.path.join(base, "cxxtest"),
os.path.join(base, "link"),
os.path.join(base, "performance")]
for directory in directories:
if not os.path.lexists(directory):
os.makedirs(directory)
def make_all(self):
print self._command
self.make_directories()
base = self.directory()
examples = glob.glob("../example/*.cc")
example_directory = os.path.join(base, "example")
for file in examples:
title = file_title(file)
if title in self._skip_examples:
continue
if title not in expected_example_outputs:
print "no expected output for example", title
sys.exit(1)
binary = os.path.join(example_directory, title) + ".exe"
command = self.elaborate("..", binary, file)
run(command, True)
output = run(binary)
output = re.sub("\r\n", "\n", output)
if output != expected_example_outputs[title]:
print output
print "output does not match expected output"
sys.exit(1)
# This is currently not done on because on Cygwin, cxxtest tries to use
# a Cygwin path to include tests.h. That path is in Unix format, which
# does not resolve to a valid path when handled by VC++. A workaround is
# to detect Cygwin and rewrite the path, but I am saving that for an
# improved version of test.py, since there are many things that need to
# be rewritten for this script to stay maintainable.
if not windows:
cxxtest_binary = os.path.join(base, "cxxtest", "tests.exe")
command = self.elaborate("..", cxxtest_binary, CXXTEST_GENERATED)
run(command, True)
run(cxxtest_binary)
link_sources = glob.glob("link/*.cc")
link_binary = os.path.join(base, "link", "link.exe")
command = self.elaborate("..", link_binary, " ".join(link_sources))
run(command, True)
performance_sources = glob.glob("performance/*.cc")
performance_directory = os.path.join(base, "performance")
for file in performance_sources:
title = file_title(file)
binary = os.path.join(performance_directory, title) + ".exe"
command = "time " + self.elaborate("..", binary, file)
output = run(command, True)
output_file = os.path.join(performance_directory, title) + ".times"
stream = open(output_file, "w")
try:
stream.write(output)
finally:
stream.close()
def directory(self):
return os.path.join(BASE_DIRECTORY, self._subdirectory)
skip_cxx98 = ["101-special-values", "102-bitset", "103-quine", "7-constexpr"]
skip_strict = ["4-switch"]
def modern_gnu(command):
return [
Configuration(command + "-c++11", command + " -std=c++11"),
Configuration(command + "-strict-conversion",
command + " -std=c++11 " +
"-DBETTER_ENUMS_STRICT_CONVERSION", skip_strict),
Configuration(command + "-all-constexpr",
command + " -std=c++11 " +
"-DBETTER_ENUMS_CONSTEXPR_TO_STRING"),
Configuration(command + "-c++98", command + " -std=c++98", skip_cxx98)
]
# g++46 should be one of these, but g++46 c++11 mode currently not supported due
# to the presence of this bug and lack of a workaround in enum.h.
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54086
def older_gnu(command):
return [
Configuration(command + "-c++0x", command + " -std=c++0x"),
Configuration(command + "-strict-conversion",
command + " -std=c++0x " +
"-DBETTER_ENUMS_STRICT_CONVERSION", skip_strict),
Configuration(command + "-all-constexpr",
command + " -std=c++0x " +
"-DBETTER_ENUMS_CONSTEXPR_TO_STRING"),
Configuration(command + "-c++98", command + " -std=c++98", skip_cxx98)
]
def gnu_pre_constexpr(command):
return [
Configuration(command + "-c++0x-noconstexpr-war",
command + " -std=c++0x " +
"-DBETTER_ENUMS_NO_CONSTEXPR", skip_cxx98),
Configuration(command + "-strict-conversion",
command + " -std=c++0x " +
"-DBETTER_ENUMS_NO_CONSTEXPR " +
"-DBETTER_ENUMS_STRICT_CONVERSION",
skip_cxx98 + skip_strict),
Configuration(command + "-c++98", command + " -std=c++98", skip_cxx98)
]
def gnu_pre_enum_class(command):
return [
Configuration(command + "-c++0x-noconstexpr-war",
command + " -std=c++0x " +
"-DBETTER_ENUMS_NO_CONSTEXPR", skip_cxx98),
Configuration(command + "-c++98", command + " -std=c++98", skip_cxx98)
]
def vc(command):
return [
Configuration(command, command + " /EHsc", skip_cxx98),
Configuration(command + "-strict-conversion",
command + " /EHsc /DBETTER_ENUMS_STRICT_CONVERSION",
skip_cxx98)
]
unix_configurations = \
modern_gnu("clang++36") + \
modern_gnu("clang++35") + \
modern_gnu("clang++34") + \
modern_gnu("clang++33") + \
modern_gnu("g++51") + \
modern_gnu("g++49") + \
modern_gnu("g++48") + \
modern_gnu("g++47") + \
gnu_pre_constexpr("g++46") + \
gnu_pre_constexpr("g++45") + \
gnu_pre_constexpr("g++44") + \
gnu_pre_enum_class("g++43")
windows_configurations = vc("vc2015") + vc("vc2013")
unix_default = Configuration("default", "c++ --std=c++11")
windows_default = Configuration("default", "cl /EHsc")
def main():
global quiet
global windows
load_expected_outputs()
run("cxxtestgen --error-printer -o %s %s" %
(CXXTEST_GENERATED, CXXTEST_SOURCE))
if re.search("Windows|CYGWIN", platform.system()) != None:
full = windows_configurations
default = windows_default
windows = True
else:
full = unix_configurations
default = unix_default
if len(sys.argv) > 1 and sys.argv[1] == "--all":
configurations = full
quiet = True
else:
configurations = [default]
quiet = False
for configuration in configurations:
configuration.make_all()
if __name__ == "__main__":
main()