diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 856971c..0000000 --- a/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -*.h linguist-language=C++ -*.tmpl linguist-language=HTML diff --git a/README.md b/README.md index 87bacfa..03a5b01 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,15 @@ # Better Enums -Reflective compile-time C++ enum library with clean syntax, in a single header -file. For example: +Reflective compile-time enum library with clean syntax, in a single header +file. - #include - ENUM(Channel, uint8_t, Red = 1, Green, Blue) +![Better Enums code overview][sample] -defines a type `Channel`. You can then do natural things such as: +[sample]: https://raw.githubusercontent.com/aantron/better-enums/0.10.1/doc/image/sample.gif -```cpp -Channel channel = Channel::Green; +[![Try online][wandbox-img]][wandbox] [![0.10.1][version]][releases] -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 -} - -// Automatic case checking, just as with a built-in enum. -switch (channel) { - case Channel::Red: break; - case Channel::Green: break; - case Channel::Blue: break; -} -``` - -...and more. You can try it live [here][wandbox]. - -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 @@ -48,13 +24,19 @@ 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 -[wandbox]: http://melpon.org/wandbox/permlink/pdlAAGoxnjqG6FRI +[wandbox]: http://melpon.org/wandbox/permlink/pdlAAGoxnjqG6FRI +[tutorial]: http://aantron.github.io/better-enums#Tutorial +[api]: http://aantron.github.io/better-enums/ApiReference.html +[releases]: https://github.com/aantron/better-enums/releases + +[wandbox-img]: https://img.shields.io/badge/try%20it-online-blue.svg +[version]: https://img.shields.io/badge/version-0.10.1-lightgrey.svg ## Installation Simply add `enum.h` to your project — that's it. -Then, include it and use the `ENUM` macro. Your compiler will generate the rich +Then, include it, and use the `ENUM` macro. Your compiler will generate the rich enums that are missing from standard C++. ## Additional features @@ -66,10 +48,10 @@ enums that are missing from standard C++. compiler as much as [just including `iostream` does][performance]. - Use any initializers and sparse ranges, just like with a built-in enum. - Guaranteed size and alignment — you choose the representation type. -- Stream operators supported. +- Stream operators. - Does not use the heap and can be compiled with exceptions disabled, for use in minimal freestanding environments. -- The underlying type [can be an object type][underlying]. +- The underlying type [does not have to be an integral type][underlying]. [performance]: http://aantron.github.io/better-enums/Performance.html [underlying]: http://aantron.github.io/better-enums/demo/NonIntegralUnderlyingTypes.html @@ -78,7 +60,7 @@ enums that are missing from standard C++. The biggest limitation is that the `ENUM` macro can't be used inside a class. This seems [difficult to remove][nested]. There is a workaround with `typedef` -(or `using`): +(or C++11 `using`): ```cpp ENUM(UniquePrefix_Color, uint8_t, Red, Green, Blue) @@ -95,20 +77,34 @@ You can, however, use `ENUM` inside a namespace. [nested]: http://aantron.github.io/better-enums/DesignDecisionsFAQ.html#NoEnumInsideClass -## Contact +## Contact and development Don't hesitate to contact me about features or bugs: [antonbachin@yahoo.com][email], Twitter [@better_enums][twitter], or open an issue on GitHub. -[email]: mailto:antonbachin@yahoo.com -[twitter]: https://twitter.com/better_enums +If you'd like to help develop Better Enums, see [CONTRIBUTING][contributing]. + +[![master kept stable][stable]][commits] [![Travis status][travis-img]][travis] +[![AppVeyor status][appveyor-img]][appveyor] + +[email]: mailto:antonbachin@yahoo.com +[twitter]: https://twitter.com/better_enums +[contributing]: https://github.com/aantron/better-enums/blob/master/doc/CONTRIBUTING.md +[stable]: https://img.shields.io/badge/master-kept_stable-brightgreen.svg +[commits]: https://github.com/aantron/better-enums/blob/master/doc/CONTRIBUTING.md#commits + +[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 and history -Better Enums is released under the BSD 2-clause license. See -[LICENSE](https://github.com/aantron/better-enums/blob/master/LICENSE). +Better Enums is released under the BSD 2-clause license. See [LICENSE][license]. 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`. + +[license]: https://github.com/aantron/better-enums/blob/master/doc/LICENSE diff --git a/CONTRIBUTING.md b/doc/CONTRIBUTING.md similarity index 85% rename from CONTRIBUTING.md rename to doc/CONTRIBUTING.md index a51ca67..67b82f8 100644 --- a/CONTRIBUTING.md +++ b/doc/CONTRIBUTING.md @@ -25,6 +25,10 @@ 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 @@ -59,6 +63,11 @@ 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, diff --git a/CONTRIBUTORS b/doc/CONTRIBUTORS similarity index 100% rename from CONTRIBUTORS rename to doc/CONTRIBUTORS diff --git a/doc/DesignDecisionsFAQ.md b/doc/DesignDecisionsFAQ.md index 674b724..232285f 100644 --- a/doc/DesignDecisionsFAQ.md +++ b/doc/DesignDecisionsFAQ.md @@ -196,6 +196,9 @@ However, it also introduces some difficulties. - 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. - Traits types are not intuitive for some $cxx users, which would present a barrier to usage. @@ -239,6 +242,32 @@ data structures — something I haven't gotten to yet because there doesn't seem to be a data structure to measure that is not disqualified by the speed of generation. +### Why not use indices for the representation? + +Representing Better Enum values by their indices in the declaration list seems +like a tempting solution for the problem of having multiple constants with the +same numeric value. It also speeds up some operations. For example, if a Better +Enum is simply an index, then getting its string representation is simply +indexing an array, rather than some kind of data structure lookup. + + // Representations 0, 1, 2, 3 instead of 1, 2, 3, 1. + ENUM(Kind, int, A = 1, B, C, D = A) + +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 diff --git a/LICENSE b/doc/LICENSE similarity index 100% rename from LICENSE rename to doc/LICENSE diff --git a/doc/Makefile b/doc/Makefile index d16fcd8..701e693 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -8,9 +8,9 @@ html : .PHONY : publish publish : prepare - cp -r html ../doc-publish - git commit --amend - git push -f + cp -r html/* ../doc-publish + cd ../doc-publish && git add . && git commit --amend --reset-author && \ + git push -f .PHONY : prepare prepare : examples web diff --git a/doc/better-enums.css b/doc/better-enums.css index f9ca9bf..7d5d1f8 100644 --- a/doc/better-enums.css +++ b/doc/better-enums.css @@ -577,3 +577,7 @@ h3.contents { .buttons-bar iframe.gh-watch { width: 103px; } + +.external { + font-size: 75%; +} diff --git a/doc/docs.py b/doc/docs.py index 36c49e3..8160116 100755 --- a/doc/docs.py +++ b/doc/docs.py @@ -140,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")) diff --git a/doc/image/sample.gif b/doc/image/sample.gif new file mode 100644 index 0000000..db7c96b Binary files /dev/null and b/doc/image/sample.gif differ diff --git a/doc/index.md b/doc/index.md index 7c53d94..e0a8596 100644 --- a/doc/index.md +++ b/doc/index.md @@ -202,6 +202,11 @@ Try it live online in
  • Design decisions FAQ
  • +
  • + + Implementation [CodeProject] + +
  • diff --git a/doc/template/footer.tmpl b/doc/template/footer.tmpl index 2d96811..ee50977 100644 --- a/doc/template/footer.tmpl +++ b/doc/template/footer.tmpl @@ -4,7 +4,8 @@