Compare commits

..

110 Commits

Author SHA1 Message Date
Anton Bachin
520d8ee390 Update copyright year 2024-01-07 15:20:03 +03:00
Chris Heyes
d65550f378
Turn off clang-format (#118)
Turns off clang-format for easier usage in projects using it.
2024-01-07 15:18:17 +03:00
Anton Bachin
1e8f499ddf Update copyright year 2021-09-09 14:18:02 +03:00
Anton Bachin
f3ff0a6917 Remove version link from README
[skip ci]
2020-11-08 08:37:41 +03:00
Anton Bachin
68ca02d1f5 Replace tab by spaces
[skip ci]
2020-11-08 08:28:09 +03:00
Anton Bachin
517387fba0 Docs: rely on GitHub issues only for contact
[skip ci]
2020-10-19 09:11:14 +03:00
Anton Bachin
fb8b398b02 README: remove link to magic_enum
There are now several alternative enum libraries, so the README no
longer seems to be a convenient place for linking them. At this point,
they should be quite discoverable on their own.

See https://github.com/aantron/better-enums/issues/89#issuecomment-706870187.
Closes #78.

[skip ci]
2020-10-19 09:05:45 +03:00
Anton Bachin
c35576bed0 Docs: update version number
[skip ci]
2020-10-19 08:45:29 +03:00
Anton Bachin
2422dd6f26 Docs: remove Wandbox link
[skip ci]
2020-10-19 08:45:17 +03:00
Anton Bachin
894eab5284 Fix some code formatting
[skip ci]
2020-10-19 08:42:50 +03:00
Anton Bachin
fd646ae537 Document BETTER_ENUMS_CLASS_ATTRIBUTE
Follow-on to #80.

[skip ci]
2020-10-19 08:33:38 +03:00
Anton Bachin
abb693d4ef Document BETTER_ENUMS_DECLARE_STD_HASH
Follow-on to #77.

[skip ci]
2020-10-19 08:26:14 +03:00
Anton Bachin
2f1fcaae7a Docs: fix rendering of <Enum>
[skip ci]
2020-10-19 08:12:51 +03:00
Anton Bachin
3e115c0c17 Rename argument of _to_index, _from_index
Follow-on to #59.
2020-10-19 08:09:55 +03:00
Anton Bachin
c730fc8ae8 Document _to_index, _from_index, etc.
Follow-on to #59.

[skip ci]
2020-10-19 08:07:45 +03:00
Anton Bachin
f480b7ef1c Remove Patreon link
[skip ci]
2020-10-18 22:32:01 +03:00
Anton Bachin
1a3c4f9e5a Tweak note about magic_enum
Resolves #88.

[skip ci]
2020-10-08 21:50:05 +03:00
Anton Bachin
21c374914c Try GitHub Sponsors
[skip ci]
2020-01-23 01:53:00 +03:00
Jan-Gerd Tenberge
dcbd3c0554 Add BETTER_ENUMS_IGNORE_ATTRIBUTES_* for clang (#81) 2020-01-13 15:40:59 +03:00
Anton Bachin
89bc057a63 Update copyright year
[skip ci]
2020-01-01 18:16:19 +03:00
CJ Smith
5dcd59bd29 Ignores -Wattributes for GCC 7 and 8 to mask compiler bug. (#79)
See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89325
This bug produces massive amounts of spurious warnings and is present
in the version of g++ currently available in RHEL devtoolset-7 and devtoolset-8.
2019-12-07 08:15:47 +03:00
Michael Ernst
fa39f5c89e Add macro BETTER_ENUMS_CLASS_ATTRIBUTE for adding attributes to enum class (#80)
When not set it defaults to empty macro.
2019-12-06 23:23:25 +03:00
Anton Bachin
4b76e7783b Recommend magic_enum
[skip ci]
2019-08-17 23:06:40 +03:00
Anton Bachin
1ea7f04bb9 Move LICENSE so that GitHub recognizes it
[skip ci]
2019-07-25 20:16:35 +03:00
Anton Bachin
e1756cdb07 Docs: remove unnecessary scroll bars
[skip ci]
2019-07-25 20:14:08 +03:00
Sven Scharmentke
5a677ac72b Support using better-enum as key in dictionaries and maps (#77)
This enabled hashing so that unordered_map are supported.
2019-07-16 12:36:16 +03:00
Felipe Lema
8a0d376b53 fix -wold-style-cast (#74) 2019-06-19 12:47:57 -05:00
Anton Bachin
8b4d8a9499 Bump version to 0.11.2
[skip ci]
2019-04-02 10:01:36 -05:00
Anton Bachin
ebc0c0138e Fix some long lines 2019-04-02 09:49:47 -05:00
Anton Bachin
b838852ff4 Remove stray comment
[skip ci]
2019-04-02 09:47:53 -05:00
Anton Bachin
f626bcde1a Docs: note maps are also specialized for wchar_t
Follow-on to #44.

[skip ci]
2019-04-02 09:29:02 -05:00
Xeverous
509c544d0f removed tabs in unwanted places (#72)
2 lines had tabs in the middle of the code, between spaces. This can
cause warnings in some tools and red markings in Git when commiting
code (tabs are to be used only as the starting characters, never after
any character).

After this commit, there are no tabs in the file at all.
2019-04-02 09:28:40 -05:00
D4koon
ed21395b20 Fix for Visual Studio 2017 (#70) 2018-11-28 03:28:05 -06:00
Anton Bachin
2d2a6a5648 AppVeyor: test on Visual Studio 2017
This commit also drops testing on Visual Studio 2008-2012, as they seem
not to be supported by the AppVeyor image.
2018-11-28 02:30:59 -06:00
Anton Bachin
882dd9cd1b Travis: allow Clang 3.3 build to fail
There seems to be some upstream bit rot with Clang++ 3.3. This is a
pretty old version, and we may want to just stop testing on it. However,
in the meantime, it will be allowed to fail without failing the overall
build.

Resolves #63.

[skip appveyor]
2018-10-19 12:37:03 -05:00
Wojciech Bartnik
94f8f95a26 Added syntax highlight (#67) 2018-10-19 12:32:40 -05:00
Felix Dombek
df5df3924e Changed identifiers beginning with underscore followed by uppercase letters. (#62)
These are in violation of the C++ standard. Renamed by lowercasing the
offending letters.

Affected identifiers:

- _Iterable -> _iterable
- _PutNamesInThisScopeAlso -> _putNamesInThisScopeAlso
_ _enumClassForSwitchStatements -> _enumClassForSwitchStatements
2018-09-19 13:31:42 -05:00
Piotr Kosek
97d38d8077 Added indexable properties on enums (#59)
- _to_index which return value 0... size-1
        (even if enums are note sequential)
 - _from_index used for other way around
 - _from_index_nothrow no throw version
 - _from_index_unchecked returns invalid enum
        in case arg>=size

Code and test cases added.
No documentation updates (my English is too poor for that)
2018-09-06 17:39:31 -05:00
Anton Bachin
e5549fb18c Docs: add notes about enabling C4062 on msvc
Resolves #49.

[skip ci]
2018-08-07 16:00:36 -05:00
Anton Bachin
21417b76b9 Doc generator: remove stale tweet image references
[skip ci]
2018-08-07 15:56:33 -05:00
Anton Bachin
3558c94cc7 README: add some whitespace
[skip ci]
2018-08-07 15:37:26 -05:00
Zsolt Parragi
2fad3f60ee Enabled constexpr support for Visual Studio 2017 2017-09-14 22:42:11 -05:00
Anton Bachin
ecdc88f066 Fix Travis build
It seems that the g++4.5 package has been obsoleted:

  https://travis-ci.org/aantron/better-enums/jobs/271125909#L492

There also seems to be some kind of upstream problem with clang++3.5
when building in C++14 mode:

  https://travis-ci.org/aantron/better-enums/jobs/271125912#L1349

To unblock development, this commit removes the g++4.5 build, and allows
the clang++3.5 build to fail for now.

[skip appveyor]
2017-09-14 13:35:28 -05:00
cheny
73a1619cb7 Specialize map_compare for wchar_t (#44)
Add the template partial specialization:
    struct map_compare<const wchar_t*> {...}
2017-07-13 06:20:57 -05:00
Anuradha Dissanayake
6988e0509e Fix /W4 level warnings in MSVC++ 2015 (#41)
Remove unused variable names and use underlying class for enum (VS 2012
and above support strongly typed enums and will warn about incorrect
usage).
2017-07-02 10:30:01 -05:00
cheparukhin
37d8f987ca Add unused attribute to free functions (#27) 2016-07-19 00:18:33 +01:00
Zsolt Parragi
ab4c8583db Enabled constepxr support for clang-cl. 2016-07-09 14:50:19 +02:00
cheparukhin
f520b397e3 Merge pull request #22 from cheparukhin/master
Fix name resolution errors
2016-07-08 19:50:32 +01:00
cheparukhin
c71b891c87 Add test for ostream operator 2016-07-08 19:50:04 +01:00
cheparukhin
d94b21a7e0 Resolve clashing global and nested namespace names
Using better_enums as a nested namespace name along a global better_enums namespace resulted in name clashes.
2016-06-22 15:52:35 +01:00
cheparukhin
9e522eaf3c Move stream I/O operators to enum namespace
Stream I/O operators defined in a global namespace caused name resolution errors in some cases.
2016-06-22 15:47:29 +01:00
Anton Bachin
18cbeb0808 Simplified README. 2016-03-15 18:29:12 -05:00
Anton Bachin
2d6b337419 Bumped version to 0.11.1. 2016-03-14 10:51:05 -05:00
Mitsutaka Takeda
e6e8e24f5c Fixed old-style cast warnings. 2016-03-12 20:33:33 -06:00
Anton Bachin
a500851e28 Documentation nits. 2016-03-03 10:12:48 -06:00
Anton Bachin
cc9cce28ae Enabled more warnings during testing.
To avoid problems with warnings in CxxTest, the extra warnings are
enabled during one test (linking) that does not use CxxTest.

Resolves #16.
2016-02-27 00:53:35 -06:00
Anton Bachin
9a754681c9 Local testing on more versions of Clang. 2016-02-27 00:19:50 -06:00
Mikhail Ovchinnikov
76ad2256dd Removed double underscores from macro names.
Names containing (and not only beginning with) double underscores are
reserved in C++.

Resolves #15.
2016-02-24 12:24:56 -06:00
Anton Bachin
f45897fcb3 README nit. 2016-02-12 12:27:11 -06:00
Anton Bachin
472a33fb64 Incorporated errata.
Fixes #13.
Fixes #14.

[ci skip]
2015-12-10 18:02:33 -06:00
Anton Bachin
f148cc4314 Disabled constexpr testing on MSVC.
Until recently, CMake reported VS2015 as not supporting constexpr.
However, constexpr support was added in the VS2015 release, and CMake
now reports accordingly.

The constexpr support in VS2015 is too buggy to build Better Enums.
This change disables testing on VS2015 with constexpr support, because
those tests will fail.

Also adapted to a change in the Cygwin path prefix in AppVeyor and
fixed an issue in the Travis build with wget being unable to retrieve
from www.cmake.org's new redirect to cmake.org.
2015-11-17 15:17:15 -06:00
Anton Bachin
e8d51bdd8e Fixed README. 2015-10-07 11:18:51 -05:00
Anton Bachin
d99bae7284 Updated documentation. 2015-10-06 15:19:39 -05:00
Anton Bachin
e9b6792922 Reordered some member functions.
Microsoft's incomplete constexpr implementation does not currently
allow constexpr use of constexpr functions that are defined out of line
below their point of use. The reordering in this commit is a
workaround.

While this still doesn't give MSVC constexpr support due to additional
bugs in Microsoft's implementation, maintaining the member functions in
this order makes it easier to begin each attempt to work around the
remaining compiler bugs.
2015-10-05 13:15:04 -05:00
Anton Bachin
8061c24191 Added Clang++ 3.7 to test matrix. 2015-10-05 13:15:04 -05:00
Anton Bachin
fc0b0de647 Made default constructor customizable by a macro.
By default, Better Enums will generate with an inaccessible (private or
deleted) default constructor. However, if the user defines
BETTER_ENUMS_DEFAULT_CONSTRUCTOR(Enum), the expansion of that macro
will be used instead. The macro approach was chosen because the
expansion can include access modifiers and fragments such as
"= default".

Resolves #10.
2015-10-04 19:03:21 -05:00
Anton Bachin
1620410372 Fixed example/Makefile. 2015-10-04 18:37:23 -05:00
Anton Bachin
9a2389cd15 Eliminated non-integral underlying types.
This was an experimental feature. Removing it to simplify maintenance.
2015-10-04 18:34:57 -05:00
Anton Bachin
c1d4a1c006 Fixed #ifdef that caused some tests not to run.
Disabled some tests that were failing due to unsupported type traits in
Travis standard library installation.
2015-10-04 12:34:19 -05:00
Anton Bachin
e1e237a4ea Renamed top-level macro ENUM to BETTER_ENUM.
To reduce name clashes.

Fixes #11.
2015-10-04 11:03:08 -05:00
Anton Bachin
977f8ef145 Replaced testing on G++ 5.1 with G++ 5.2.
GCC 5.2 is a "bugfix" release over GCC 5.1 - not sure why the GCC team
updated the minor version number. Package managers seem to have dropped
GCC 5.1 and replaced it with 5.2, and I'm guessing usage of 5.1 is
discouraged. The testing code has been updated accordingly.

Travis is still distributing GCC 5.1 as of the time of this writing.
2015-08-23 12:41:42 -05:00
Anton Bachin
0595a526e7 Updated AppVeyor configuration.
Since VS2015 RTM, AppVeyor provides an image that has both VS2015 and
Cygwin pre-installed. Before this change, I had combined the build
matrix into one row, because of the need to install Cygwin in each
build worker, which is a 10-15-minute process. Since this is no longer
necessary, the matrix is restored. AppVeyor builds are now very fast.
2015-08-23 12:38:56 -05:00
Anton Bachin
eac6afacdc Bidirectional maps between enums and any types.
Also added a C++14 configuration to testing, but using it only for
bidrectional map testing at the moment.
2015-07-11 19:32:28 -05:00
Anton Bachin
0f816be0cd Restored clang 3.6 and 3.5 in the Travis build.
Now that llvm.org is back up and Travis is able to download the
compiler binaries.
2015-07-11 17:29:09 -05:00
Anton Bachin
60a4f4dfda Updated documentation. 2015-07-11 15:27:43 -05:00
Anton Bachin
f404ea709b Made N4428 implementation more exact.
See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4428.pdf
2015-07-11 15:25:48 -05:00
Anton Bachin
30efe7ccd7 Temporarily removed clang 3.5 and 3.6 in Travis.
I am still testing against these locally. Travis is having difficulty
installing them in build instances, perhaps due to the current llvm.org
outage.
2015-07-11 15:19:34 -05:00
Anton Bachin
6c3d02b951 Fixed bug that disallowed some constant names.
The user-supplied constant names are used to declare an internal enum
type. They end up sharing a namespace with some internal library
values. Those internal values had names not prefixed with underscores.
As a result, it was impossible to declare enum constants with these
names.

Prefixed the internal names with underscores.
2015-07-11 10:23:34 -05:00
Anton Bachin
f1a0b5d0e4 Simple implementation of N4428 enum reflection. 2015-07-09 18:29:44 -05:00
Anton Bachin
b182e16ec3 Local testing on VC2010 and VC2012.
Also improved the documentation Makefile not to re-generate the samples
unless the source Markdown files are newer. This should make samples
development easier.
2015-07-09 18:28:11 -05:00
Anton Bachin
9273051e07 Updated documentation and appearance. 2015-07-09 00:38:45 -05:00
Anton Bachin
7cfd738c1a Included VC2008 in AppVeyor and local testing.
Also reordered compilers so that the very first tested are the ones
that support the most configurations, then immediately followed by
those which are the most likely to fail. Typically, this would be the
oldest ones, or the compiler versions that were the first to support
some major features.
2015-07-08 09:25:48 -05:00
Anton Bachin
6278793a0b Added workarounds for VC2008.
VC2008 has two quirks. It generates linking errors if a copy
constructor is not explicitly defined on a Better Enum, and it has a
buggy interaction between the ternary operator and throw. This change
detects VC2008 and generates alternative code for that compiler.

Having an explicitly-defined copy constructor in a literal type appears
to cause an internal compiler error in g++4.7, and causes a spurious
compilation failure in g++4.8. For this reason, the copy constructor
generation is conditioned on the compiler.

The replacement code for the ternary operator is also generated
conditionally, because it uses an if-statement. The normal code has to
compile in a constexpr context, and so has to use the ternary operator
instead of the if-statement.

Resolves #6.
2015-07-07 11:22:40 -05:00
Anton Bachin
124c09f2f0 Sped up the AppVeyor build.
Current AppVeyor images with VC2015 don't have Cygwin pre-installed, so
each row in the build matrix installs it before running the build. This
takes about 7-8 minutes per row.

This change combines all the VC testing into one row, so the price of
installing Cygwin is paid only once. A secondary improvement is that
individual rows don't have to wait in the AppVeyor queue. Builds now
take a total of about 15 minutes, instead of approximately an hour,
including queueing time.

This change should probably be undone once there is an AppVeyor image
that comes with both VC2015 and Cygwin. The main AppVeyor image has VC
up to 2013 and Cygwin, so I suppose VC2015 and Cygwin will be available
once a final version of VC2015 is released.

Until then, Better Enums does not have the benefit of separate rows in
the AppVeyor build matrix.
2015-07-02 18:17:06 -05:00
Anton Bachin
89a1c1a64b Updated CONTRIBUTING.md and related information. 2015-07-02 16:56:33 -05:00
Alexander Buddenbrock
1769fbb6b7 Added support for testing in Travis. 2015-07-02 15:51:01 -05:00
Anton Bachin
07fef34465 Not assuming bash in testing scripts. 2015-07-02 10:56:37 -05:00
Anton Bachin
3c3733c700 Support for testing in AppVeyor.
Tests are run for VC2010, VC2012, VC2013, VC2015.
2015-07-01 23:58:23 -05:00
Anton Bachin
ba9139e075 Switched to CMake for building tests.
To run tests with the system compiler, execute

    make

To run tests with the system compiler in all configurations,

    make default-all

To re-generate the examples from the documentation Markdown, and then
test all configurations,

    make default-thorough

Other Makefile targets are for exhaustive testing with multiple
locally-installed compilers, or for use on CI servers, and are not for
general use.

Python and CxxTest are still required. On Windows, it is helpful to
have a Cygwin environment with a non-Cygwin CMake, and MSBuild.exe
should be in PATH.

Better Enums is now tested in fewer configurations. C++11 features are
no longer tested on clang 3.3, gcc 4.3-4.6, because CMake claims
(apparently falsely, in some cases) that those compilers don't support
constexpr and enum class.
2015-07-01 15:18:48 -05:00
Anton Bachin
535f7f151b Fixed char16_t and char32_t detection for clang.
These are now only assumed in C++11 mode. long long is also assumed
only in C++11 mode for clang, which may make some programs that rely on
long long as an extension in C++98 fail with Better Enums. I will solve
that at a later date if it becomes a problem.
2015-07-01 15:11:29 -05:00
Alexander Buddenbrock
54b7a054be Only apply the Cygwin fix on Windows.
The so called 'cygwin_fix_command' replaces all instances of '/home'
with 'C:/cygwin/home'. This will cause the tests to fail on linux as
this directory does not exist there.
2015-06-27 18:30:03 -05:00
Anton Bachin
faf3676fec Made it easier to generate offline documentation.
Documentation can be generated by going to doc/ and running "make".
This requires Python. Before this change, the user had to install the
mistune library, which is used by the generator. The mistune library is
now included in the Better Enums distribution.

The generated docs are available at doc/html/index.html. Note that some
links won't be local (the GitHub repo, the download link, outgoing
links to MSDN, tutorial source in the GitHub repo, and so on). All the
pages belonging to the actual docs will be local, however.

The online version of the docs can be generated by running "make web".
The only difference between the online and offline versions is that the
former includes Google Analytics tracking code, and may include social
communication buttons, comment section, or other useless things in the
future.

Also included errata since the last release.

Resolves #2.
2015-06-27 13:56:27 -05:00
Anton Bachin
9a02379937 Updated README. 2015-06-20 17:00:49 -05:00
Anton Bachin
f5f669277a Updated documentation. 2015-06-20 13:11:56 -05:00
Anton Bachin
d90bfd6f18 Fixed some warnings with strict flags. 2015-06-20 11:50:26 -05:00
Anton Bachin
9810dd07ce Changed _size to a function.
An alternative constant _size_constant is provided for use in C++98,
for example for declaring arrays.

Also renamed underlying_traits to integral_mapping.
2015-06-19 17:05:33 -05:00
Anton Bachin
aa34aad468 Simplified underlying type traits.
Removed the function are_equal. Comparison is now done by converting
operands to their integral representation, and comparing those. Also
restored ordering of enum values along the same lines (according to
integral representation).
2015-06-15 19:29:39 -05:00
Anton Bachin
a493e90ac4 Initialization now always completed before main.
Before this change, in C++98 and C++11 "fast" mode, initializer
trimming was done "lazily" the first time _to_string or _names was
called. To make performance more "predictable", an object with static
storage is now used to force initializaton during program start-up,
when static object constructors are called.

The benefit of this change is very debatable. I had to give the static
object static linkage to avoid duplicate symbols, so there is a copy
now in each translation unit. I hope this does not increase code size
too much in realistic scenarios.

Lazy initialization checks are still performed and cannot be removed,
because other objects with static storage may try to use an enum from
their constructors before the enum's initialization is forced.
2015-06-15 18:32:57 -05:00
Anton Bachin
fc609e58aa Internal clean-up. 2015-06-15 10:48:05 -05:00
Anton Bachin
74b3a66284 Eliminated dynamic allocation.
When compile-time stringized constant name trimming is disabled (off by
default), trimming happens "lazily" - the first time the user calls a
function such as _to_string, the function allocates space for trimmed
constant names and trims them there.

With this change, space is reserved statically in a writeable char
array, and trimming happens in that array instead.
2015-06-13 16:22:07 -05:00
Anton Bachin
98232ee4fb Made enum.h build with exceptions disabled.
Throwing functions are simply omitted.
2015-06-12 17:17:41 -05:00
Anton Bachin
7502ae3c18 Included enum type names in exception messages. 2015-06-12 14:06:59 -05:00
Anton Bachin
11a1c26494 Internal improvements to stream operators. 2015-06-12 12:56:51 -05:00
Anton Bachin
0f63667106 Overloaded stream operators.
To avoid paying the huge penalty of including iostream and string for
users that don't need those headers, and to avoid creating a second,
optional header file, I resorted to defining the operators as templates
to prevent type checking until the user tries to actually use them. The
stream types and strings are wrapped in a metafunction that depends on
the template parameter. This is basically a hack, but it seems to work.
2015-06-11 23:05:46 -05:00
Anton Bachin
4314ad3fd3 Experimental generalization of underlying types.
With this change, the underlying type can be a non-integral type that
provides conversions to and from an integral type. See the test at
test/cxxtest/underlying.h for some examples - though they are more
verbose than strictly necessary, for testing needs.

Move constructors in underlying types are not supported. It has been
difficult so far to get constexpr code not to select the move
constructor, which is generally not constexpr, for various operations.
2015-06-11 20:39:46 -05:00
Anton Bachin
b037d8b5eb Improved test.py to for multiple test files and Cygwin. 2015-06-10 15:58:32 -05:00
Anton Bachin
5edcb3e121 Made ENUM usable in namespaces. 2015-06-07 17:05:31 -05:00
Anton Bachin
97197088fe Updated contact information and other errata. 2015-06-06 13:54:40 -05:00
Anton Bachin
820fd22b5f Added CONTRIBUTING file and acknowledgements. 2015-06-05 21:57:33 -05:00
Anton Bachin
41508fb114 Eliminated underscored internal macro names.
Also made a few documentation changes.
2015-06-05 19:20:18 -05:00
90 changed files with 4747 additions and 1396 deletions

2
.gitattributes vendored
View File

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

1
.github/FUNDING.yml vendored Normal file
View File

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

2
.gitignore vendored
View File

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

38
.travis.yml Normal file
View File

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

View File

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

125
README.md
View File

@ -1,39 +1,21 @@
# Better Enums
# Better Enums &nbsp; [![Try online][wandbox-img]][wandbox] [![Travis status][travis-img]][travis] [![AppVeyor status][appveyor-img]][appveyor]
Reflective compile-time C++ enum library with clean syntax, in a single header
file. For example:
[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
#include <enum.h>
ENUM(Channel, int, Red = 1, Green, Blue)
Reflective compile-time enum library with clean syntax, in a single header
file, and without dependencies.
defines a type `Channel`. You can then do natural things such as:
![Better Enums code overview][sample]
```cpp
Channel channel = Channel::Green;
[sample]: https://raw.githubusercontent.com/aantron/better-enums/master/doc/image/sample.gif
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,
In C++11, *everything* can be used 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
@ -45,40 +27,77 @@ built into C++98.
See the [project page][project] for full documentation.
[max]: http://aantron.github.io/better-enums/demo/BitSets.html
[enforce]: http://aantron.github.io/better-enums/demo/SpecialValues.html
[project]: http://aantron.github.io/better-enums
[max]: http://aantron.github.io/better-enums/demo/BitSets.html
[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 &mdash; that's it.
Simply add `enum.h` to your project.
Then, include it and use the `ENUM` macro. Your compiler will generate the rich
enums that are missing from standard C++.
<br/>
## Additional features
- 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.
- 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].
- Fast compilation. You have to declare a few dozen enums to slow down your
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.
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.
[testing]: http://aantron.github.io/better-enums/CompilerSupport.html
[performance]: http://aantron.github.io/better-enums/Performance.html
## Contact
<br/>
Don't hesitate to contact me about features or bugs:
[antonbachin@yahoo.com](mailto:antonbachin@yahoo.com), or open an issue on
GitHub.
## Limitations
## License and history
1. The biggest limitation is that the `BETTER_ENUM` macro can't be used inside a
class. This seems [difficult to remove][nested]. There is a workaround with
`typedef` (or C++11 `using`):
Better Enums is released under the BSD 2-clause license. See
[LICENSE](https://github.com/aantron/better-enums/blob/master/LICENSE).
```c++
BETTER_ENUM(SomePrefix_Color, uint8_t, Red, Green, Blue)
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`.
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`.

29
appveyor.yml Normal file
View File

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

View File

@ -7,7 +7,7 @@ $internal_toc
The declaration
#include <enum.h>
<em>ENUM</em>(<em>Enum</em>, <em>underlying_type</em>, <em>A</em>, <em>B</em>, <em>C</em>, ...)
<em>BETTER_ENUM</em>(<em>Enum</em>, <em>underlying_type</em>, <em>A</em>, <em>B</em>, <em>C</em>, ...)
generates a new class type `Enum` which is notionally similar to the type
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>ENUM</em>(Enum, underlying_type, <em>A</em> = <em>1</em>, <em>B</em> = <em>constant_expression</em>, <em>C</em> = <em>A</em>, ...)
<em>BETTER_ENUM</em>(Enum, underlying_type, <em>A</em> = <em>1</em>, <em>B</em> = <em>constant_expression</em>, <em>C</em> = <em>A</em>, ...)
The initializers have the same meaning and constraints as in a built-in `enum`
or `enum class` declaration.
---
The principal differences between the types declared by the `ENUM` macro and
`enum class` are:
The principal differences between the types declared by the `BETTER_ENUM` macro
and `enum class` are:
- `ENUM` is available for $cxx98
- `BETTER_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 `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 `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 types produced by the `ENUM` macro are called *Better Enums* in the rest of
this reference.
The types produced by the `BETTER_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>ENUM</em>(<em>Enum</em>, <em>int</em>, <em>A</em>, <em>B</em>, <em>C</em>)
<em>BETTER_ENUM</em>(<em>Enum</em>, <em>int</em>, <em>A</em>, <em>B</em>, <em>C</em>)
@ -69,8 +69,8 @@ rest of the documentation.
#### <em>typedef _enumerated</em>
An internal type used to declare constants. The `ENUM` macro generates something
similar to
An internal type used to declare constants. The `BETTER_ENUM` macro generates
something similar to
~~~comment
<em>struct Enum</em> {
@ -150,9 +150,14 @@ 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`.
The number of constants declared. `Enum::_size() == 3`.
#### static constexpr const size_t <em>_size_constant</em>
Same as [`_size`](#_size), but a constant instead of a function. This is
provided for use in $cxx98 constant expressions.
#### <em>typedef _value_iterable</em>
@ -223,7 +228,7 @@ If the given string is the exact name of a declared constant, returns the
constant. Otherwise, throws `std::runtime_error`. Running time is linear in the
number of declared constants multiplied by the length of the longest constant.
#### static constexpr optional<Enum> <em>_from_string_nothrow</em>(const char*)
#### static constexpr optional&lt;Enum&gt; <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.
@ -233,7 +238,7 @@ failure. Returns an [optional value](#StructBetter_enumsoptional) instead.
Same as [`_from_string`](#_from_string), but comparison is up to case, in the
usual sense in the Latin-1 encoding.
#### static constexpr optional<Enum> <em>_from_string_nocase_nothrow</em>(const char*)
#### static constexpr optional&lt;Enum&gt; <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
@ -255,7 +260,7 @@ case as in [`_from_string_nocase`](#_from_string_nocase).
Evaluates to the name of the Better Enum type. `Enum::_name()` is the same
string as `"Enum"`.
#### typedef <em>_name_iterable</em>
#### <em>typedef _name_iterable</em>
Type of object that permits iteration over names of declared constants. Has at
least `constexpr` `begin()`, `end()`, and `size()` methods. `operator[]` is also
@ -263,7 +268,7 @@ available, but is `constexpr` if and only if [`_to_string`](#_to_string) is
`constexpr`. Iteration visits constants in order of declaration. See usage
example under [`_names`](#_names).
#### typedef <em>_name_iterator</em>
#### <em>typedef _name_iterator</em>
Random-access iterator type for `_name_iterable`. Most operations are
`constexpr`, but dereferencing is `constexpr` if and only if
@ -322,7 +327,7 @@ example,
(+<em>Enum::C</em>)<em>._to_integral</em>() == <em>2</em>
Note that Better Enums are already implicitly convertible to their underlying
integral types [by default](${prefix}OptInFeatures.html#StrictConversion).
integral types [by default](${prefix}OptInFeatures.html#StrictConversions).
You may still want to use this function, however, for clarity, and to ensure
that your code remains compatible if the strict conversions feature is enabled
later.
@ -337,7 +342,7 @@ of one of the declared constants.
<em>Enum::_from_integral</em>(<em>2</em>); // Enum::C
<em>Enum::_from_integral</em>(<em>42</em>); // std::runtime_error
#### static constexpr optional<Enum> <em>_from_integral_nothrow</em>(_integral)
#### static constexpr optional&lt;Enum&gt; <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)
@ -365,6 +370,64 @@ constants.
### Index lookup
#### member constexpr std::size_t <em>_to_index</em>() const
Returns the index of a Better Enum value within its enum declaration. The index
is determined from the value only; if two constants in the declaration have the
same value, this function may return the index of either constant.
If the value does not correspond to any constant in the declaration (for
example, if it was obtained using an unchecked conversion or a cast), then the
behavior of `value._to_index` is undefined.
#### static constexpr Enum <em>_from_index</em>(size_t)
Returns the value of the constant with the given index. Throws
`std::runtime_error` if not given the index of one of the constants.
#### static constexpr Enum <em>_from_index_unchecked</em>(size_t)
Returns the value of the constant with the given index. If not given one of the
constants in the declaration of the enum, the returned value is undefined.
#### static constexpr optional&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.

94
doc/CONTRIBUTING.md Normal file
View File

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

11
doc/CONTRIBUTORS Normal file
View File

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

View File

@ -1,11 +1,10 @@
## Compiler support
Better Enums aims to support all major compilers. It is known to definitely work
on
Better Enums aims to support all major compilers. It is known to work on:
- clang 3.3 to 3.6
- gcc 4.3 to 5.1
- Visual C++ 2013U4, 2015RC.
- clang 3.3 to 3.9
- gcc 4.3 to 5.3
- Visual C++ 2008 to 2015.
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
@ -76,6 +75,21 @@ 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
@ -88,14 +102,11 @@ clang++34 -std=c++11
clang++34 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
clang++34 -std=c++11 -DBETTER_ENUMS_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++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++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++49 -std=c++11
g++49 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
g++49 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
@ -108,17 +119,12 @@ g++47 -std=c++11
g++47 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
g++47 -std=c++11 -DBETTER_ENUMS_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 = Information about compiler support and feature detection.
%% description =
Better Enums compiler support, compatibility, feature detection, and automated
testing.

View File

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

269
doc/DesignDecisionsFAQ.md Normal file
View File

@ -0,0 +1,269 @@
## Design decisions FAQ
$be pushes at the edges of what is possible in standard $cxx, and I've had to
make some difficult decisions as a result. You can imagine the set of
potential reflective enum implementations as a space, with axes such as "concise
syntax," "uniform interface," "compilation speed," "run-time performance," and
so on. As is typical in engineering, the constraints are such that as you move
to extremes along one axis, you have to retreat along others &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 `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 `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
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/$version/script/make_macros.py" download>GitHub</a>.
or from <a href="https://raw.githubusercontent.com/aantron/better-enums/$ref/script/make_macros.py" download>GitHub</a>.
3. You will run this script to generate a header file containing some
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,10 +31,38 @@ 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.
%% description = How to extend limits imposed by internal macros.
---
I am paying attention to feedback, so if more than a few users say that the
default limit of 64 constants is too low, I will increase it to simplify
everyone's command line. The current choice of 64 is basically an arbitrary
guess, loosely informed by the following two facts about macro parameter limits:
- The default limit in Boost.Preprocessor is 64. Though Better Enums does not
use Boost, I took this number as a guideline.
- The next power of two, 128, is more than [the number Visual C++ supports][vc]
(127).
[vc]: https://msdn.microsoft.com/en-us/library/ft39hh4x.aspx
%% description =
How to extend limits imposed by internal macros in Better Enums.

View File

@ -1,23 +1,36 @@
SOURCE_MARKDOWN := $(wildcard tutorial/*) $(wildcard demo/*)
SOURCE_CXX := $(SOURCE_MARKDOWN:.md=.cc)
toexample = ../example/$(notdir $(1:.md=.cc))
.PHONY : all
all : html examples
SOURCE_MARKDOWN := $(wildcard tutorial/*.md) $(wildcard demo/*.md)
SOURCE_CXX := $(foreach md,$(SOURCE_MARKDOWN),$(call toexample,$(md)))
.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 : clean-examples $(SOURCE_CXX)
examples : $(SOURCE_CXX)
.PHONY : clean-examples
clean-examples :
make -C ../example clean
rm -f ../example/*.cc
define EXAMPLE
$(1) : $(2)
python transform.py --o-cxx $(1) $(2)
endef
%.cc : %.md
python transform.py --o-cxx ../example/$(notdir $@) $<
$(foreach md,$(SOURCE_MARKDOWN), \
$(eval $(call EXAMPLE,$(call toexample,$(md)),$(md))))
.PHONY : clean
clean :

View File

@ -6,6 +6,27 @@ 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.
@ -22,7 +43,8 @@ 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 `ENUM` and deprecate it, so your code will still work.
redefine `SLOW_ENUM` as `BETTER_ENUM` and deprecate it, so your code will still
work.
### Strict conversions
@ -64,5 +86,17 @@ Here they are:
case <em>+</em>Channel::Blue: break;
}
%% description = Opting into features disabled by default for performance or
compatibility reasons.
%% 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> {

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

View File

@ -11,13 +11,19 @@ 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: scroll;
overflow: auto;
color: rgba(255, 255, 255, 0.6);
font-size: 78%;
max-width: 84ex;
margin-left: 1em;
}
pre em {
@ -45,21 +51,35 @@ code, samp {
}
.container {
max-width: 760px;
margin-left: 230px;
margin-left: 150px;
margin-right: 150px;
}
@media (max-width: 1220px) {
.main .container > * {
max-width: 41em;
}
.index .main .container > * {
max-width: none;
}
.main .container > .contents {
max-width: none;
}
@media (max-width: 1400px) {
.container {
margin-left: auto;
margin-right: auto;
width: 1100px;
}
}
@media (max-width: 780px) {
@media (max-width: 1120px) {
.container {
margin-left: 10px;
margin-right: 10px;
width: auto;
}
}
@ -79,6 +99,17 @@ 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;
}
@ -103,13 +134,38 @@ header {
background: linear-gradient(#395E7E, #4A79A0);
color: white;
padding: 50px 0;
margin-bottom: 50px;
}
h1 {
margin: 0;
font-size: 60px;
font-weight: 100;
font-weight: normal;
text-shadow: -2px 2px rgba(0, 0, 0, 0.3);
}
header section {
float: left;
}
header section.buttons, header section.notes {
float: right;
margin-top: 1.75em;
margin-left: 20px;
}
header section.notes {
max-width: 20em;
font-size: 75%;
margin-right: 10px;
opacity: 0.7;
}
header section.notes p {
margin: 0.35em 0.35em;
}
header section.notes code {
background-color: transparent;
}
header h2 {
@ -129,10 +185,41 @@ 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: 100;
font-weight: 300;
}
hr {
@ -142,20 +229,20 @@ hr {
footer {
font-size: 14px;
margin-top: 150px;
margin-top: 100px;
margin-bottom: 20px;
opacity: 0.6;
opacity: 0.5;
}
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 {
@ -166,6 +253,10 @@ header a:hover {
text-decoration: none;
}
.main {
margin-top: 50px;
}
.main a[href], footer a[href] {
background-color: #edd;
color: #844;
@ -215,7 +306,6 @@ span#note:target {
.main h3 {
font-size: 30px;
font-weight: 100;
margin-top: 2em;
color: black;
}
@ -288,15 +378,45 @@ li {
}
.blurbs > li {
width: 45%;
float: left;
min-height: 5em;
}
.blurbs > li.even {
clear: both;
margin-left: 3%;
margin-right: 6%;
@media (min-width: 1076px) {
.blurbs > li {
width: 28%;
margin-right: 4%;
}
.blurbs > li.zero-mod-three {
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;
}
}
.blurbs strong {
@ -311,19 +431,6 @@ 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%;
@ -342,9 +449,25 @@ 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;
}
@ -354,12 +477,22 @@ li {
.splash pre.left {
text-align: right;
color: inherit;
color: black;
font-weight: bold;
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) {
@ -385,6 +518,7 @@ h4 {
color: #888;
padding-top: 1em;
white-space: nowrap;
font-size: 125%;
}
h4 em {
@ -394,9 +528,9 @@ h4 em {
}
.api ul.contents {
-webkit-columns: 300px 2;
-moz-columns: 300px 2;
columns: 300px 2;
-webkit-columns: 300px 3;
-moz-columns: 300px 3;
columns: 300px 3;
}
.api ul.contents > li {
@ -407,6 +541,7 @@ h4 em {
.main h3 {
margin-top: 4em;
clear: both;
}
h3.contents {
@ -425,3 +560,36 @@ 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:
ENUM(<em>Channel</em>, int, Red, Green, Blue, <em>Invalid</em>)
BETTER_ENUM(<em>Channel</em>, int, Red, Green, Blue, <em>Invalid</em>)
// Invalid is the invalid value by default
ENUM(<em>Compression</em>, int, <em>Undefined</em>, None, Huffman)
BETTER_ENUM(<em>Compression</em>, int, <em>Undefined</em>, None, Huffman)
OVERRIDE_INVALID(<em>Compression</em>, <em>Undefined</em>)
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
ENUM(<em>Answer</em>, int, Yes, No, <em>Invalid</em>)
BETTER_ENUM(<em>Answer</em>, int, Yes, No, <em>Invalid</em>)
// OVERRIDE_DEFAULT(<em>Answer</em>, <em>Invalid</em>)
you will get a helpful compile-time error saying
@ -170,5 +170,6 @@ There are many possible variations of these policies, but I think most of them
can be encoded in a reasonable fashion using the tools Better Enums provides.
Enjoy!
%% description = Encoding project policies for static enforcement using Better
Enums.
%% 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.

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,10 +38,10 @@ 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.
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)
BETTER_ENUM(<em>EFLAGS</em>, int,
<em>Carry</em>, <em>Parity</em> = 2, <em>Adjust</em> = 4, <em>Zero</em>, <em>Sign</em>, <em>Trap</em>, <em>Interrupt</em>, <em>Direction</em>,
<em>Overflow</em>, <em>NestedTask</em> = 14, <em>Resume</em> = 16, <em>V8086</em>, <em>AlignmentCheck</em>,
<em>CPUIDPresent</em> = 21)
int main()
{
@ -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 constant for use in
declaring bit set types.
%% description = Finding the maximum value of a Better Enum for use in declaring
statically-sized 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 `ENUM` declaration and also stringizes it.
expands to an `BETTER_ENUM` declaration and also stringizes it.
But that's not the point here. The point of this page is to show some of the
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:
ENUM(<em>Channel</em>, int, Red, Green, Blue)
ENUM(<em>Depth</em>, int, TrueColor = 1, HighColor = 0)
BETTER_ENUM(<em>Channel</em>, int, Red, Green, Blue)
BETTER_ENUM(<em>Depth</em>, int, TrueColor = 1, HighColor = 0)
@ -82,7 +82,7 @@ initializers for sequential values, but I won't go through this exercise here.
constexpr <em>size_t constants_length</em>(size_t index = 0, size_t accumulator = 0)
{
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("ENUM(")
<em>string_length("BETTER_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>"ENUM(%s, int", Enum::_name()</em>);
offset += std::sprintf(buffer, <em>"BETTER_ENUM(%s, int", Enum::_name()</em>);
<em>for</em> (<em>Enum value</em> : <em>Enum::_values()</em>) {
offset +=
@ -166,8 +166,10 @@ Now, we can write and run this code.
It prints:
~~~comment
ENUM(Channel, int, Red = 0, Green = 1, Blue = 2)
ENUM(Depth, int, TrueColor = 1, HighColor = 0)
BETTER_ENUM(Channel, int, Red = 0, Green = 1, Blue = 2)
BETTER_ENUM(Depth, int, TrueColor = 1, HighColor = 0)
~~~
%% description = Contrived example that shows static memory allocation.
%% description = Have a Better Enum print its own definition. Shows how to
compute the amount of memory necessary from the reflective information provided
by a Better Enum.

View File

@ -0,0 +1,173 @@
## C++17 reflection proposal
*You can try this demo [live online][live].*
Better Enums can be used to implement the enums portion of the
[$cxx17 reflection proposal N4428][n4428] in $cxx11. N4428 proposes the
following traits interface:
~~~comment
<em>namespace std {
template <typename E>
struct enum_traits {
struct enumerators {
constexpr static size_t size;
template <size_t I>
struct get {
constexpr string_literal identifier;
constexpr static E value;
};
};
};
}</em>
~~~
So, the basic usage would be:
~~~comment
<em>enum class Foo {A, B, C};
constexpr size_t size =
std::enum_traits<Foo>::enumerators::size;
constexpr Foo value_0 =
std::enum_traits<Foo>::enumerators::get<0>::value;
constexpr string_literal name_1 =
std::enum_traits<Foo>::enumerators::get<1>::identifier;</em>
~~~
Resulting in the values `3`, `Foo::A`, and `"B"`, respectively.
---
The interface is implemented in the optional header file
[`extra/better-enums/n4428.h`][header]. There is a necessary difference: the
interface is only available for enums declared through the `BETTER_ENUM` macro.
This is because the macro is what generates the information necessary for
reflection.
### Demo
So, with that out of the way, we can do a little test. Let's assume that
`extra/` has been added as a directory to search for include files.
#ifndef BETTER_ENUMS_CONSTEXPR_TO_STRING
#define BETTER_ENUMS_CONSTEXPR_TO_STRING
#endif
#include <iostream>
<em>#include</em> <<em>enum.h</em>>
<em>#include</em> <<em>better-enums/n4428.h</em>>
---
Let's declare an enum:
<em>BETTER_ENUM</em>(<em>Channel</em>, <em>char</em>, <em>Red</em> = <em>1</em>, <em>Green</em>, <em>Blue</em>)
...and try N4428:
constexpr std::size_t <em>size</em> =
<em>std</em>::<em>enum_traits</em><<em>Channel</em>>::<em>enumerators</em>::<em>size</em>;
constexpr Channel <em>value_0</em> =
<em>std</em>::<em>enum_traits</em><<em>Channel</em>>::<em>enumerators</em>::<em>get</em><<em>0</em>>::<em>value</em>;
constexpr Channel <em>value_1</em> =
<em>std</em>::<em>enum_traits</em><<em>Channel</em>>::<em>enumerators</em>::<em>get</em><<em>1</em>>::<em>value</em>;
constexpr const char *<em>identifier_2</em> =
<em>std</em>::<em>enum_traits</em><<em>Channel</em>>::<em>enumerators</em>::<em>get</em><<em>2</em>>::<em>identifier</em>;
...and check the results:
static_assert(<em>size</em> == <em>3</em>, "");
static_assert(<em>value_0</em> == +<em>Channel::Red</em>, "");
static_assert(<em>value_1</em> == +<em>Channel::Green</em>, "");
int main()
{
std::cout << <em>identifier_2</em> << std::endl;
return 0;
}
That prints `Blue`, as you would expect.
### Quirk
The reason for the `#define` in the code above is that there is one quirk:
the interface above is available only for Better Enums for which
[compile-time name trimming][slow-enum] is enabled &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,6 +7,8 @@ import string
import transform
import os
import os.path
import sys
import urllib
TEMPLATE_DIRECTORY = "template"
OUTPUT_DIRECTORY = "html"
@ -83,15 +85,24 @@ 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 '$' in text:
text = apply_template(text, definitions)
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
text = "<!-- Generated automatically - edit the templates! -->\n\n" + text
@ -129,7 +140,9 @@ def compose_general_page(relative_path):
write_page(relative_path, text)
def list_general_pages():
return glob.glob("*.md")
return filter(
lambda s: not os.path.splitext(os.path.basename(s))[0].isupper(),
glob.glob("*.md"))
def process_threaded(directory):
sources = glob.glob(os.path.join(directory, "*.md"))
@ -143,7 +156,7 @@ def process_threaded(directory):
source_file = \
os.path.splitext(os.path.basename(file))[0] + "." + CXX_EXTENSION
source_link = "$repo/blob/$version/example/" + source_file
source_link = "$repo/blob/$ref/example/" + source_file
definitions[directory + "_body"] = definitions["body"]
definitions["body"] = templates[directory]
@ -183,6 +196,10 @@ 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"
@ -192,6 +209,9 @@ 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)

BIN
doc/image/sample.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

View File

@ -1,9 +1,3 @@
Better Enums is a single header file that causes your compiler to generate
*reflective* enum types. This makes it easy to translate between enums and
strings, and much more.
Here's how to use a Better Enum:
<div class="splash">
<pre class="left">enable
@ -11,7 +5,7 @@ declare
parse
print
format
count
@ -19,6 +13,7 @@ iterate
switch
@ -29,22 +24,25 @@ switch
safe cast
at compile time</pre>
<pre class="right"><em>#include</em> &lt;<em>enum.h</em>&gt;
during
compilation
</pre>
<pre class="right"><em>#include &lt;enum.h&gt;</em>
<em>ENUM</em>(<em>Channel</em>, <em>int</em>, <em>Red</em> = <em>1</em>, <em>Green</em>, <em>Blue</em>)
<em>BETTER_ENUM(Channel, int, Red = 1, Green, Blue)</em>
Channel c = <em>Channel::_from_string("Red")</em>;
const char *s = <em>c._to_string()</em>;
size_t n = <em>Channel::_size</em>;
<em>for</em> (<em>Channel c</em> : <em>Channel::_values()</em>)
run_some_function(<em>c</em>);
size_t n = <em>Channel::_size()</em>;
<em>for (Channel c : Channel::_values())</em> {
run_some_function(c);
}
<em>switch</em> (<em>c</em>) {
<em>switch (c)</em> {
<em>case Channel::Red</em>: // ...
<em>case Channel::Green</em>: // ...
<em>case Channel::Blue</em>: // ...
@ -54,32 +52,57 @@ size_t n = <em>Channel::_size</em>;
Channel c = <em>Channel::_from_integral(3)</em>;
<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>
### What do you get?
<p class="splash-text">
$be is a single, lightweight header file that makes your compiler generate
<em>reflective</em> enum types.
</p>
That means you can easily convert enums to and from strings,
validate them, and loop over them. In $cxx11, you can do it all at
compile time.
It's what built-in enums ought to support. Better Enums simply adds the missing
features. And, it is based on the best known techniques, thoroughly tested,
fast, portable, and documented exhaustively.
To use it, just include <code>enum.h</code> and begin the
[tutorial](${prefix}tutorial/HelloWorld.html)!
<div class="hack"></div>
### Highlights
<ul class="blurbs">
<li class="even">
<strong>Uniform interface for $cxx98 and $cxx11</strong>
<em>Scoped, sized, reflective enums for $cxx98.</em>
</li>
<li>
<strong>Compile-time reflection</strong>
<li class="zero-mod-two zero-mod-three">
<strong>Unobtrusive syntax</strong>
<em>
Have the compiler do additional enum processing using your own
templates or <code>constexpr</code> functions.
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>
<li class="even">
<strong>Non-contiguous sequences</strong>
<li class="one-mod-two one-mod-three">
<strong>No external dependencies</strong>
<em>
Iteration and count much easier to maintain than with an extra "count"
constant and making assumptions.
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>
<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
@ -87,15 +110,7 @@ Channel c = <em>Channel::_from_integral(3)</em>;
</em>
</li>
<li class="even">
<strong>Unobtrusive syntax</strong>
<em>
No ugly macros. Use initializers just like with built-in
<code>enums</code>. Generated members have underscores to avoid conflicts
with your constant names.
</em>
</li>
<li>
<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
@ -103,29 +118,48 @@ Channel c = <em>Channel::_from_integral(3)</em>;
</em>
</li>
<li class="even">
<strong>No build-time generator needed</strong>
<li class="one-mod-two two-mod-three">
<strong>Non-contiguous sequences</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>.
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="even">
<strong>No external dependencies</strong>
<li class="zero-mod-two zero-mod-three">
<strong>Fast compilation</strong>
<em>
Uses standard $cxx and supported on major compilers. Installation is
simple &mdash; just download <code>enum.h</code>.
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>
<li class="one-mod-two one-mod-three">
<strong>Compile-time reflection</strong>
<em>
Have the compiler do additional enum processing using your own
templates or <code>constexpr</code> functions.
</em>
</li>
<li class="zero-mod-two two-mod-three">
<strong>Uniform interface for $cxx98, $cxx11</strong>
<em>
Scoped, sized, reflective enums for $cxx98, and an easy upgrade
path.
</em>
</li>
<li class="one-mod-two zero-mod-three">
<strong>Stream operators</strong>
<em>
Write enum names directly to <code>std::cout</code> or use
<code>boost::lexical_cast</code>.
</em>
</li>
<li class="zero-mod-two one-mod-three">
<strong>Free and open source</strong>
<em>
Released under the BSD license for use in any project, free or commercial.
@ -135,40 +169,18 @@ Channel c = <em>Channel::_from_integral(3)</em>;
<div class="hack"></div>
### 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
### Documentation
<ul class="blurbs resources">
<li class="even">
<li class="zero-mod-two zero-mod-three">
<a id="Tutorial"></a>
<strong>Tutorial</strong>
<ol>
$tutorial_toc
</ol>
</li>
<li>
<li class="one-mod-two one-mod-three">
<strong>Reference</strong>
<ul>
<li><a href="${prefix}ApiReference.html">API reference</a></li>
@ -176,12 +188,20 @@ The library notionally <em>extends</em> $cxx, adding oft-needed features.
<li><a href="${prefix}OptInFeatures.html">Opt-in features</a></li>
<li><a href="${prefix}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="even">
<li class="zero-mod-two two-mod-three">
<a id="CompileTimeDemos"></a>
<strong>Compile-time demos</strong>
<strong>Advanced</strong>
<ul>
$demo_toc
</ul>
@ -192,8 +212,8 @@ The library notionally <em>extends</em> $cxx, adding oft-needed features.
%% title = Clean reflective enums for C++
%% 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.
%% 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.
%% class = index

1102
doc/mistune.py Executable file

File diff suppressed because it is too large Load Diff

View File

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

1
doc/template/cxx14.tmpl vendored Normal file
View File

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

1
doc/template/cxx17.tmpl vendored Normal file
View File

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

View File

@ -1,7 +1,7 @@
<p>
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.
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.
</p>
$demo_body

View File

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

View File

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

10
doc/template/ga.tmpl vendored Normal file
View File

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

1
doc/template/ghfork.tmpl vendored Normal file
View File

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

1
doc/template/ghstar.tmpl vendored Normal file
View File

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

1
doc/template/ghwatch.tmpl vendored Normal file
View File

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

View File

@ -13,6 +13,8 @@
<link rel="stylesheet" href="${prefix}better-enums.css" />
$ga
</head>
<body class="$class">
@ -23,7 +25,6 @@
<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>
@ -31,11 +32,24 @@
<header>
<div class="container">
<div class="back">{}</div>
<section>
<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>
<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 class="notes">
<p>Version $version</p>
<p>To install, just add <code>enum.h</code> to your project.</p>
<p>
Visit the GitHub repo for issues, feedback, and the latest development.
</p>
</section>
<section class="buttons">
<a $download>Download <code>enum.h</code></a>
<a href="$repo">GitHub</a>
</section>
</div>
</header>

1
doc/template/ref.tmpl vendored Normal file
View File

@ -0,0 +1 @@
0.11.3

View File

@ -1,6 +1,7 @@
<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.
valid program, which you can <a href="$source">download</a> and play with. The
program runs as part of the automated test suite.
</p>
$tutorial_body

View File

@ -1 +1 @@
0.9.0
0.11.3

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

View File

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

View File

@ -6,12 +6,12 @@ example, this:
#include <iostream>
#include <enum.h>
<em>ENUM(Channel, int, Red, Green = 2, Blue)</em>
<em>BETTER_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,4 +46,5 @@ If you are using $cxx11, you can have much nicer syntax:
return 0;
}
%% description = Iterating over all Better Enums constants.
%% description = Using Better Enums to iterate over all the constants of an
enum, as well as over its names. Also shows the same with C++11 for-each syntax.

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>ENUM(Channel, int, Red, Green, Blue)</em>
<em>BETTER_ENUM(Channel, int, Red, Green, Blue)</em>
int main()
{
@ -21,10 +21,16 @@ A Better Enum can be used directly in a `switch` statement:
If you miss a case or add a redundant one, your compiler should be able to give
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 = Usage in switch statements.
%% description = Better Enums can be used directly in switch statements like
normal enums, making it possible for the compiler to check that all cases are
listed, increasing the safety of your code.

77
doc/tutorial/5-map.md Normal file
View File

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

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

View File

@ -3,6 +3,12 @@
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
@ -12,7 +18,7 @@ You have probably noticed by now that Better Enums are scoped: when you declare
#include <cassert>
<em>#include <enum.h></em>
<em>ENUM</em>(<em>Channel</em>, <em>int</em>, <em>Red</em> = <em>1</em>, <em>Green</em>, <em>Blue</em>)
<em>BETTER_ENUM</em>(<em>Channel</em>, <em>int</em>, <em>Red</em> = <em>1</em>, <em>Green</em>, <em>Blue</em>)
you don't get names such as `Red` in the global namespace. Instead, you get
`Channel`, and `Red` is accessible as `Channel::Red`. This is no big deal in
@ -20,7 +26,7 @@ $cxx11, which has `enum class`. In $cxx98, however, this typically requires
effort. Better Enums brings scope uniformly to both variants. So, despite the
above declaration, you can safely declare
<em>ENUM</em>(<em>Node</em>, <em>char</em>, <em>Red</em>, <em>Black</em>)
<em>BETTER_ENUM</em>(<em>Node</em>, <em>char</em>, <em>Red</em>, <em>Black</em>)
and everything will work as expected.
@ -47,33 +53,27 @@ 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 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:
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:
~~~comment
Channel channel;
~~~
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.
If this is too strict for your project, you can relax it as described
[here](${prefix}OptInFeatures.html#DefaultConstructors).
---
return 0;
}
%% description = Type safety features and limitations.
%% description = Better Enums type safety features and limitations.

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

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>ENUM</em>(<em>Channel</em>, <em>int</em>, <em>Red</em> = <em>1</em>, <em>Green</em> = <em>2</em>, <em>Blue</em> = <em>3</em>)
<em>BETTER_ENUM</em>(<em>Channel</em>, <em>int</em>, <em>Red</em> = <em>1</em>, <em>Green</em> = <em>2</em>, <em>Blue</em> = <em>3</em>)
<em>constexpr</em> Channel channel = <em>Channel::_from_integral(2)</em>;
<em>constexpr</em> int value = <em>channel._to_integral()</em>;
@ -48,4 +48,5 @@ You can also do things such as:
Which prints "5", the length of "Green". That 5 was also computed during
compilation.
%% description = Introduction to compile-time conversions.
%% description = Better Enums can be used entirely at compile time in C++11. All
conversion functions are available for constexpr functions or templates.

1468
enum.h

File diff suppressed because it is too large Load Diff

View File

@ -2,12 +2,12 @@
// Hello, World!
//
// Download enum.h, then build this program with it:
// Download enum.h, then compile this program:
#include <iostream>
#include "enum.h"
ENUM(Word, int, Hello, World)
BETTER_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:
ENUM(Channel, int, Red, Green, Blue, Invalid)
BETTER_ENUM(Channel, int, Red, Green, Blue, Invalid)
// Invalid is the invalid value by default
ENUM(Compression, int, Undefined, None, Huffman)
BETTER_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
ENUM(Answer, int, Yes, No, Invalid)
BETTER_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,10 +38,10 @@ 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.
ENUM(EFLAGS, int,
Carry, Parity = 2, Adjust = 4, Zero, Sign, Trap, Interrupt, Direction,
Overflow, NestedTask = 14, Resume = 16, V8086, AlignmentCheck,
CPUIDPresent = 21)
BETTER_ENUM(EFLAGS, int,
Carry, Parity = 2, Adjust = 4, Zero, Sign, Trap, Interrupt, Direction,
Overflow, NestedTask = 14, Resume = 16, V8086, AlignmentCheck,
CPUIDPresent = 21)
int main()
{

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 ENUM declaration and also stringizes it.
// macro that expands to an BETTER_ENUM declaration and also stringizes it.
//
// But that's not the point here. The point of this page is to show some of the
// 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:
ENUM(Channel, int, Red, Green, Blue)
ENUM(Depth, int, TrueColor = 1, HighColor = 0)
BETTER_ENUM(Channel, int, Red, Green, Blue)
BETTER_ENUM(Depth, int, TrueColor = 1, HighColor = 0)
@ -79,7 +79,7 @@ template <typename Enum>
constexpr size_t constants_length(size_t index = 0, size_t accumulator = 0)
{
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("ENUM(")
string_length("BETTER_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, "ENUM(%s, int", Enum::_name());
offset += std::sprintf(buffer, "BETTER_ENUM(%s, int", Enum::_name());
for (Enum value : Enum::_values()) {
offset +=
@ -163,5 +163,5 @@ int main()
// It prints:
//
// ENUM(Channel, int, Red = 0, Green = 1, Blue = 2)
// ENUM(Depth, int, TrueColor = 1, HighColor = 0)
// BETTER_ENUM(Channel, int, Red = 0, Green = 1, Blue = 2)
// BETTER_ENUM(Depth, int, TrueColor = 1, HighColor = 0)

View File

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

View File

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

View File

@ -8,12 +8,12 @@
#include <iostream>
#include <enum.h>
ENUM(Channel, int, Red, Green = 2, Blue)
BETTER_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>
ENUM(Channel, int, Red, Green, Blue)
BETTER_ENUM(Channel, int, Red, Green, Blue)
int main()
{
@ -22,6 +22,8 @@ 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;

74
example/5-map.cc Normal file
View File

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

30
example/6-iostreams.cc Normal file
View File

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

View File

@ -5,6 +5,12 @@
// 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
@ -13,7 +19,7 @@
#include <cassert>
#include <enum.h>
ENUM(Channel, int, Red = 1, Green, Blue)
BETTER_ENUM(Channel, int, Red = 1, Green, Blue)
// you don't get names such as Red in the global namespace. Instead, you get
// Channel, and Red is accessible as Channel::Red. This is no big deal in C++11,
@ -21,7 +27,7 @@ ENUM(Channel, int, Red = 1, Green, Blue)
// Better Enums brings scope uniformly to both variants. So, despite the above
// declaration, you can safely declare
ENUM(Node, char, Red, Black)
BETTER_ENUM(Node, char, Red, Black)
// and everything will work as expected.
@ -45,28 +51,20 @@ int main()
// The reason this is not enabled by default is explained in the reference page
// 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 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:
// 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:
//
// Channel channel;
//
// 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.
// If this is too strict for your project, you can relax it as described here.
return 0;

View File

@ -9,7 +9,7 @@
#include <iostream>
#include <enum.h>
ENUM(ContentType, short,
BETTER_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>
ENUM(Channel, int, Red = 1, Green = 2, Blue = 3)
BETTER_ENUM(Channel, int, Red = 1, Green = 2, Blue = 3)
constexpr Channel channel = Channel::_from_integral(2);
constexpr int value = channel._to_integral();

View File

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

View File

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

View File

@ -3,18 +3,19 @@
# 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.
# 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.
# You only need this script if you are developing enum.h, or run into a limit.
#
# _ENUM_PP_MAP has a limit, which determines the maximum number of constants an
# enum can have. By default, this limit is 64 constants.
# 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_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).
# 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).
#
# 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
@ -28,7 +29,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 declared.
# or use any other method of getting these macros defined.
# 3. Compile your code. Your macro file should be included, and enum.h should
# happily work with whatever limits you chose.
@ -66,35 +67,38 @@ def generate(stream, constants, length, script):
print >> stream, ''
print >> stream, '#pragma once'
print >> stream, ''
print >> stream, '#ifndef _BETTER_ENUM_MACRO_FILE_H_'
print >> stream, '#define _BETTER_ENUM_MACRO_FILE_H_'
print >> stream, '#ifndef BETTER_ENUMS_MACRO_FILE_H'
print >> stream, '#define BETTER_ENUMS_MACRO_FILE_H'
print >> stream, ''
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, '#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, ' (macro, data, __VA_ARGS__))'
print >> stream, ''
print >> stream, '#define _ENUM_PP_MAP_VAR_COUNT(count) ' + \
'_ENUM_M ## count'
print >> stream, '#define BETTER_ENUMS_PP_MAP_VAR_COUNT(count) ' + \
'BETTER_ENUMS_M ## count'
print >> stream, ''
print >> stream, '#define _ENUM_A(macro, ...) _ENUM_ID(macro(__VA_ARGS__))'
print >> stream, '#define BETTER_ENUMS_APPLY(macro, ...) ' + \
'BETTER_ENUMS_ID(macro(__VA_ARGS__))'
print >> stream, ''
print >> stream, '#define _ENUM_ID(x) x'
print >> stream, '#define BETTER_ENUMS_ID(x) x'
print >> stream, ''
print >> stream, '#define _ENUM_M1(m, d, x) m(d,0,x)'
print >> stream, '#define BETTER_ENUMS_M1(m, d, x) m(d,0,x)'
for index in range(2, constants + 1):
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, '#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, ''
pp_count_impl_prefix = '#define _ENUM_PP_COUNT_IMPL(_1,'
pp_count_impl_prefix = '#define BETTER_ENUMS_PP_COUNT_IMPL(_1,'
stream.write(pp_count_impl_prefix)
pp_count_impl = MultiLine(stream = stream, indent = 4,
initial_column = len(pp_count_impl_prefix))
@ -106,10 +110,11 @@ def generate(stream, constants, length, script):
print >> stream, ''
print >> stream, ''
print >> stream, '#define BETTER_ENUMS_PP_COUNT(...) \\'
pp_count_prefix = \
'#define _ENUM_PP_COUNT(...) _ENUM_ID(_ENUM_PP_COUNT_IMPL(__VA_ARGS__,'
' BETTER_ENUMS_ID(BETTER_ENUMS_PP_COUNT_IMPL(__VA_ARGS__,'
stream.write(pp_count_prefix)
pp_count = MultiLine(stream = stream, indent = 4,
pp_count = MultiLine(stream = stream, indent = 8,
initial_column = len(pp_count_prefix))
for index in range(0, constants - 1):
pp_count.write(' ' + str(constants - index) + ',')
@ -117,7 +122,7 @@ def generate(stream, constants, length, script):
print >> stream, ''
print >> stream, ''
iterate_prefix = '#define _ENUM_ITERATE(X, f, l)'
iterate_prefix = '#define BETTER_ENUMS_ITERATE(X, f, l)'
stream.write(iterate_prefix)
iterate = MultiLine(stream = stream, indent = 4,
initial_column = len(iterate_prefix))
@ -126,7 +131,7 @@ def generate(stream, constants, length, script):
print >> stream, ''
print >> stream, ''
print >> stream, '#endif // #ifndef _BETTER_ENUM_MACRO_FILE_H_'
print >> stream, '#endif // #ifndef BETTER_ENUMS_MACRO_FILE_H'
if __name__ == '__main__':
if len(sys.argv) != 3:

203
test/CMakeLists.txt Normal file
View File

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

View File

@ -1,13 +1,167 @@
.PHONY : default
default :
make -C ../doc examples
python test.py
# 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.
.PHONY : platform
platform :
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 :
make -C ../doc examples
python test.py --all
# Example: make COMPILER=clang++36 unix
.PHONY : unix
unix :
make TITLE=$(COMPILER) CMAKE_OPTIONS="-DCMAKE_CXX_COMPILER=$(COMPILER)" \
MAKE_COMMAND=$(UNIX_MAKE_COMMAND) \
OUTPUT_DIRECTORY=$(UNIX_OUTPUT_DIRECTORY) all-configurations
# Example: make TITLE=vc2013 COMPILER="Visual Studio 12 2013" ms
.PHONY : ms
ms :
make TITLE=$(TITLE) CMAKE_OPTIONS="-G \\\"$(COMPILER)\\\"" \
MAKE_COMMAND=$(WINDOWS_MAKE_COMMAND) \
OUTPUT_DIRECTORY=$(WINDOWS_OUTPUT_DIRECTORY) all-configurations
# Expects three variables to be defined:
# CMAKE_OPTIONS:
# First, the compiler:
# - Empty for a "default" build.
# - -G "Visual Studio XX YYYY" to select a specific Microsoft compiler.
# - -DCMAKE_CXX_COMPILER=AAA to select a specific Unix compiler binary.
# Configuration selection (e.g. -DCONFIGURATION=CXX98) also go here.
# TITLE:
# The build title (subdirectory). Some combination of compiler/configuration.
# MAKE_COMMAND:
# Either make or msbuild "Better Enums Testing.sln"
# OUTPUT_DIRECTORY:
# Path to generated binaries relative to build directory. Either "." or
# "Debug".
.PHONY : one-configuration
one-configuration : $(CXXTEST_GENERATED)
mkdir -p build/$(TITLE)
cd build/$(TITLE) && cmake $(CMAKE_OPTIONS) ../.. && $(MAKE_COMMAND)
rm -rf build/$(TITLE)/bin
[ -f build/$(TITLE)/do-not-test ] || \
( ln -s $(OUTPUT_DIRECTORY) build/$(TITLE)/bin && \
make BIN=build/$(TITLE)/bin run-tests )
.PHONY : run-tests
run-tests :
$(BIN)/cxxtest
@for FILE in $(BIN)/example-*$(SUFFIX) ; \
do \
EXAMPLE=$$(basename $$FILE | sed s/\.exe$$// | sed s/^example-//) ; \
$$FILE | sed 's/\r$$//' | cmp - expect/$$EXAMPLE ; \
RESULT=$$? ; \
if [ $$RESULT -ne 0 ] ; \
then \
echo \'$$FILE\' produced bad output ; \
exit $$RESULT ; \
fi ; \
done
@echo Example program output matches expected output
.PHONY : all-configurations
all-configurations :
make TITLE=$(TITLE)-c++11 \
CMAKE_OPTIONS="$(CMAKE_OPTIONS) -DCONFIGURATION=CONSTEXPR" \
one-configuration
make TITLE=$(TITLE)-full-constexpr \
CMAKE_OPTIONS="$(CMAKE_OPTIONS) -DCONFIGURATION=FULL_CONSTEXPR" \
one-configuration
make TITLE=$(TITLE)-enum-class \
CMAKE_OPTIONS="$(CMAKE_OPTIONS) -DCONFIGURATION=STRICT_CONVERSION" \
one-configuration
make TITLE=$(TITLE)-c++14 \
CMAKE_OPTIONS="$(CMAKE_OPTIONS) -DCONFIGURATION=CXX14" \
one-configuration
make TITLE=$(TITLE)-c++98 \
CMAKE_OPTIONS="$(CMAKE_OPTIONS) -DCONFIGURATION=CXX98" \
one-configuration
.PHONY : all-unix
all-unix : examples
make COMPILER=clang++39 unix
make COMPILER=clang++38 unix
make COMPILER=clang++37 unix
make COMPILER=g++52 unix
make COMPILER=g++46 unix
make COMPILER=g++47 unix
make COMPILER=g++43 unix
make COMPILER=g++48 unix
make COMPILER=g++49 unix
make COMPILER=g++44 unix
make COMPILER=g++45 unix
make COMPILER=clang++33 unix
make COMPILER=clang++34 unix
make COMPILER=clang++35 unix
make COMPILER=clang++36 unix
.PHONY : all-ms
all-ms : examples
make TITLE=vc2015 COMPILER="Visual Studio 14 2015" ms
make TITLE=vc2008 COMPILER="Visual Studio 9 2008" ms
make TITLE=vc2010 COMPILER="Visual Studio 10 2010" ms
make TITLE=vc2012 COMPILER="Visual Studio 11 2012" ms
make TITLE=vc2013 COMPILER="Visual Studio 12 2013" ms
$(CXXTEST_GENERATED) : cxxtest/*.h
$(CXXTESTGEN) --error-printer -o $@ $^
$(call PATH_FIX,$@)
.PHONY : clean
clean :
rm -rf platform *.obj
rm -rf build $(CXXTEST_GENERATED)

View File

@ -1,3 +1,4 @@
#include <iosfwd>
#include <stdexcept>
#include <cxxtest/TestSuite.h>
#include <enum.h>
@ -12,17 +13,28 @@
ENUM(Channel, short, Red, Green, Blue)
ENUM(Depth, short, HighColor = 40, TrueColor = 20)
ENUM(Compression, short, None, Huffman, Default = Huffman)
BETTER_ENUM(Channel, short, Red, Green, Blue)
BETTER_ENUM(Depth, short, HighColor = 40, TrueColor = 20)
BETTER_ENUM(Compression, short, None, Huffman, Default = Huffman)
// 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
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)
#include <type_traits>
#include <functional>
// Type properties.
static_assert_1(std::is_class<Channel>());
@ -36,12 +48,14 @@ static_assert_1(std::is_integral<Channel::_integral>());
static_assert_1(std::is_enum<Channel::_enumerated>());
static_assert_1((std::is_same<short, Channel::_integral>()));
static_assert_1((std::is_same<
short, std::underlying_type<Channel::_enumerated>::type>()));
// 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<int, Channel::_integral>()));
static_assert_1(!(std::is_same<
int, std::underlying_type<Channel::_enumerated>::type>()));
// Temporarily disabled due to outdated libraries in Travis.
// 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));
@ -52,13 +66,16 @@ static_assert_1((std::is_same<decltype(Channel::Red), Channel::_enumerated>()));
// Supported constructors.
#ifdef __clang__
static_assert_1(std::is_trivially_copyable<Channel>());
#endif
// Apparently, this isn't supported by Clang in Travis.
// #ifdef __clang__
// static_assert_1(std::is_trivially_copyable<Channel>());
// #endif
static_assert_1((std::is_constructible<Channel, Channel::_enumerated>()));
static_assert_1(!(std::is_constructible<Channel, Channel::_integral>()));
static_assert_1(!(std::is_constructible<Channel, Depth>()));
// "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>()));
// Commented out temporarily due to GCC 4.7- bug.
// static_assert_1(!std::is_default_constructible<Channel>());
@ -106,12 +123,23 @@ static_assert_1(
static_assert_1(Channel::_is_valid("Green"));
static_assert_1(Channel::_is_valid_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)
@ -136,6 +164,24 @@ 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()
@ -210,9 +256,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);
@ -237,7 +283,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);
@ -269,4 +315,120 @@ 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)

29
test/cxxtest/stream.h Normal file
View File

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

View File

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

View File

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

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

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

View File

@ -0,0 +1 @@
Blue

4
test/expect/5-map Normal file
View File

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

1
test/expect/6-iostreams Normal file
View File

@ -0,0 +1 @@
Red

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>
ENUM(Channel, int, Red, Green, Blue)
#endif // #ifndef _SHARED_H_

View File

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

8
test/linking/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/linking/shared.h Normal file
View File

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

View File

@ -1,219 +1,223 @@
#include <enum.h>
ENUM(Channel, int,
Red, Green, Blue, Cyan, Magenta, Yellow, Black, Hue, Saturation, Value)
BETTER_ENUM(Channel, int,
Red, Green, Blue, Cyan, Magenta, Yellow, Black, Hue, Saturation,
Value)
ENUM(Direction, int,
North, East, South, West, NorthEast, SouthEast, SouthWest, NorthWest,
NorthNorthEast, EastNorthEast, EastSouthEast, SouthSouthEast,
SouthSouthWest, WestSouthWest, WestNorthWest, NorthNorthWest)
BETTER_ENUM(Direction, int,
North, East, South, West, NorthEast, SouthEast, SouthWest,
NorthWest, NorthNorthEast, EastNorthEast, EastSouthEast,
SouthSouthEast, SouthSouthWest, WestSouthWest, WestNorthWest,
NorthNorthWest)
ENUM(ASTNode, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
BasicType, ArrowType, VariantTypeConstant)
BETTER_ENUM(ASTNode, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
ENUM(State, int,
Attacking, Defending, Searching, Pursuing, Hungry, Fleeing, Confused,
Healing, Stunned)
BETTER_ENUM(State, int,
Attacking, Defending, Searching, Pursuing, Hungry, Fleeing,
Confused, Healing, Stunned)
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(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(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(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(ASTNode0, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable, UnaryOperation,
BinaryOperation, ApplicationExpression, Abstraction, LetBinding,
CaseExpression, Pattern, Signature, Module, Functor, TypeVariable,
BasicType, ArrowType, VariantTypeConstant)
BETTER_ENUM(ASTNode0, 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(ASTNode1, 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(ASTNode2, 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(ASTNode3, 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(ASTNode4, 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(ASTNode5, 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(ASTNode6, 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(ASTNode7, 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(ASTNode8, 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(ASTNode9, 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(ASTNode10, 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(ASTNode11, 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(ASTNode12, 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(ASTNode13, 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(ASTNode14, 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(ASTNode15, 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(ASTNode16, 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(ASTNode17, 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(ASTNode18, 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(ASTNode19, 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(ASTNode20, 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(ASTNode21, 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(ASTNode22, 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(ASTNode23, 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(ASTNode24, 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(ASTNode25, 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(ASTNode26, 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(ASTNode27, 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(ASTNode28, 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)
BETTER_ENUM(ASTNode29, int,
IntegerLiteral, StringLiteral, CharacterLiteral, Variable,
UnaryOperation, BinaryOperation, ApplicationExpression, Abstraction,
LetBinding, CaseExpression, Pattern, Signature, Module, Functor,
TypeVariable, BasicType, ArrowType, VariantTypeConstant)
int main()
{

View File

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