From 6551a3820dc1ab21e22748773d305d5952961b65 Mon Sep 17 00:00:00 2001 From: David Dight Date: Tue, 30 Jul 2024 08:36:44 +0000 Subject: [PATCH 001/235] updated --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index c99154e..54dde60 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,8 @@ Based on the awesome work in [`magic_enum`](https://github.com/Neargye/magic_enu this library offers a streamlined and powerful way to add reflection capabilities to your C++ enums and other types. We've optimized the core functionality, focusing on the main features developers usually want. We've also added general purpose typename reflection for any type. +For the latest cutting edge changes, see the [dev branch](https://github.com/fix8mt/conjure_enum/tree/dev). + ## b) Embracing C++20 `conjure_enum`[^1] takes full advantage of recently added C++20 features. We've leveraged the convenience of `std::source_location` and From d47ce5821239de2c958ab376a7105c7cc0a01bbb Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 31 Jul 2024 09:46:08 +0000 Subject: [PATCH 002/235] updated --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 54dde60..5da8524 100644 --- a/README.md +++ b/README.md @@ -1537,19 +1537,21 @@ $ It can be observed that there is only _one_ copy of the scoped enum value string in the executable. ## f) Clang compile profiling -You can profile the compile time for Clang (other compilers TBA). Firstly install [ClangBuildAnalyzer](https://github.com/aras-p/ClangBuildAnalyzer). Then configure with: +You can profile the compile time for Clang (other compilers TBA). Firstly install [ClangBuildAnalyzer](https://github.com/aras-p/ClangBuildAnalyzer). +Then configure `conjure_enum` with: ```CMake cmake -DBUILD_CLANG_PROFILER=true .. ``` -You can follow the instructions given on the `ClangBuildAnalyzer` page to run, alternatively after you build the included program `cbenchmark.cpp`, +You can follow the instructions given on the `ClangBuildAnalyzer` page to run. Alternatively after you build the included program `cbenchmark`, run the included script [cbenchmark.sh](examples/cbenchmark.sh). The script expects the following environment variables: | Variable | Description | | :--- | :--- | | `ClangBuildAnalyzerLoc` | directory where ClangBuildAnalyzer can be found| -| `ArtifactLoc` | directory where conjure_enum is built| +| `ArtifactLoc` | directory where `conjure_enum` is built| -For example, if `ClangBuildAnalyzer` was built in `~/prog/ClangBuildAnalyzer/build` and your `conjure_enum` build was in `./build_clang`, then: +For example, if `ClangBuildAnalyzer` was built in `~/prog/ClangBuildAnalyzer/build` and your `conjure_enum` build was in `./build_clang`, then you +would run the script from the `conjure_enum` directory as follows: ```bash ClangBuildAnalyzerLoc=~/prog/ClangBuildAnalyzer/build ArtifactLoc=build_clang examples/cbenchmark.sh ``` From 171067f09a8c4b8902b1ef43ba2faf13dad9a311 Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 31 Jul 2024 21:40:18 +0000 Subject: [PATCH 003/235] updated --- README.md | 55 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 5da8524..0b25a67 100644 --- a/README.md +++ b/README.md @@ -402,7 +402,28 @@ userinfo component::userinfo static constexpr std::array, std::size_t> rev_scoped_entries; ``` Same as `scoped_entries` except reversed, sorted by scoped name. Use to lookup unscoped name. -## m) `contains` +## m) `index` +```c++ +static constexpr std::optional index(T value); +template +static constexpr std::optional index(); +``` +Returns the index (position in 0 based array of values) of the supplied enum value `std::optional`. Empty if value was not valid. Use `std::optional::value_or()` to set an error value +and avoid throwing an exception. +```c++ +std::cout << conjure_enum::index(component::password).value() << '\n'; +std::cout << conjure_enum::index(component(100)).value_or(100) << '\n'; +std::cout << conjure_enum::index().value() << '\n'; +std::cout << conjure_enum::index().value_or(100) << '\n'; +``` +_output_ +```CSV +4 +100 <-- invalid, error value +4 +100 <-- invalid, error value +``` +## n) `contains` ```c++ static constexpr bool contains(T value); static constexpr bool contains(std::string_view str); @@ -417,7 +438,7 @@ _output_ true false ``` -## n) `for_each`, `for_each_n` +## o) `for_each`, `for_each_n` ```c++ template requires std::invocable @@ -521,7 +542,7 @@ _output_ ```CSV 160 ``` -## o) `dispatch` +## p) `dispatch` ```c++ template static constexpr bool tuple_comp(const std::tuple& pl, const std::tuple& pr); @@ -620,7 +641,7 @@ _output_ 6000 1015 ``` -## p) `is_scoped` +## q) `is_scoped` ```c++ struct is_scoped : std::integral_constant>; }>{}; @@ -635,7 +656,7 @@ _output_ true false ``` -## q) `is_valid` +## r) `is_valid` ```c++ template static constexpr bool is_valid(); @@ -650,7 +671,7 @@ _output_ true false ``` -## r) `type_name` +## s) `type_name` ```c++ static constexpr std::string_view type_name(); ``` @@ -664,7 +685,7 @@ _output_ component component1 ``` -## s) `remove_scope` ![](assets/notminimalred.svg) +## t) `remove_scope` ![](assets/notminimalred.svg) ```c++ static constexpr std::string_view remove_scope(std::string_view what); ``` @@ -678,7 +699,7 @@ _output_ path path ``` -## t) `add_scope` ![](assets/notminimalred.svg) +## u) `add_scope` ![](assets/notminimalred.svg) ```c++ static constexpr std::string_view add_scope(std::string_view what); ``` @@ -692,7 +713,7 @@ _output_ component::path path ``` -## u) `has_scope` ![](assets/notminimalred.svg) +## v) `has_scope` ![](assets/notminimalred.svg) ```c++ static constexpr bool has_scope(std::string_view what); ``` @@ -708,7 +729,7 @@ true false false ``` -## v) `iterators` +## w) `iterators` ```c++ static constexpr auto cbegin(); static constexpr auto cend(); @@ -735,7 +756,7 @@ _output_ 8 numbers::eight 9 numbers::nine ``` -## w) `iterator_adaptor` +## x) `iterator_adaptor` ```c++ template struct iterator_adaptor; @@ -758,7 +779,7 @@ _output_ 8 9 ``` -## x) `front, back` +## y) `front, back` ```c++ static constexpr auto front(); static constexpr auto back(); @@ -775,7 +796,7 @@ _output_ 0 numbers::zero 9 numbers::nine ``` -## y) `ostream_enum_operator` +## z) `ostream_enum_operator` ```c++ template, valid_enum T> constexpr std::basic_ostream& operator<<(std::basic_ostream& os, T value); @@ -797,7 +818,7 @@ _output_ "host" "100" ``` -## z) `epeek, tpeek` +## A) `epeek, tpeek` ```c++ static consteval const char *tpeek(); template @@ -817,7 +838,7 @@ static consteval const char* FIX8::conjure_enum::tpeek() [with T = component] static consteval const char* FIX8::conjure_enum::epeek() [with T e = component::path; T = component] ``` -## aa) `get_enum_min_value` and `get_enum_max_value` +## B) `get_enum_min_value` and `get_enum_max_value` ```c++ static constexpr int get_enum_min_value(); static constexpr int get_enum_max_value(); @@ -1257,11 +1278,11 @@ target_include_directories(myproj PRIVATE ${conjure_enum_SOURCE_DIR}/include) ## d) Reporting issues Raise an [issue](https://github.com/fix8mt/conjure_enum/issues) on the github page. The executable `srcloctest` should be built when you build the package by default. This application -does not use any of the `conjure_enum` library and is designed to report on how your compiler handles `std::source_location`. +does not use any of the `conjure_enum` library and is designed to report how your compiler handles `std::source_location`. The actual output is implementation dependent. See [Results of `source_location`](reference/source_location.md) for implementation specific `std::source_location` results. You should attach the output of this application with your issue. > [!TIP] -> Passing the switch `-m` causes `srcloctest` to generate github markdown which you can paste directly into the issue. +> Use the `-m` switch with `srcloctest` to generate github markdown which you can paste directly into the issue. ```C++ $ ./srcloctest From fa8b28027e580b0daac164aef9a861999862c53a Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 31 Jul 2024 21:49:18 +0000 Subject: [PATCH 004/235] updated --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 0b25a67..799e83c 100644 --- a/README.md +++ b/README.md @@ -427,16 +427,20 @@ _output_ ```c++ static constexpr bool contains(T value); static constexpr bool contains(std::string_view str); +template +static constexpr bool contains(); ``` Returns `true` if the enum contains the given value or string. ```c++ std::cout << std::format("{}\n", conjure_enum::contains(component::path)); std::cout << std::format("{}\n", conjure_enum::contains("nothing")); +std::cout << std::format("{}\n", conjure_enum::contains()); ``` _output_ ```CSV true false +true ``` ## o) `for_each`, `for_each_n` ```c++ From 97d80ae8a186d2b60be1077166c8e0fc89ef9987 Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 31 Jul 2024 22:00:06 +0000 Subject: [PATCH 005/235] pre-rel 1.0.2a --- include/fix8/conjure_enum.hpp | 13 +++++++++++++ utests/unittests.cpp | 16 ++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index eb97467..5ca96ee 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -434,6 +434,17 @@ class conjure_enum : public static_only return {}; } + // index + static constexpr std::optional index(T value) noexcept + { + if (const auto result { std::equal_range(values.cbegin(), values.cend(), value, _value_comp) }; + result.first != result.second) + return &*result.first - &*values.cbegin(); + return {}; + } + template + static constexpr std::optional index() noexcept { return index(e); } + // contains static constexpr bool contains(T value) noexcept { @@ -445,6 +456,8 @@ class conjure_enum : public static_only const auto result { std::equal_range(sorted_entries.cbegin(), sorted_entries.cend(), enum_tuple(T{}, str), _tuple_comp_rev) }; return result.first != result.second; } + template + static constexpr bool contains() noexcept { return contains(e); } // string <==> enum template diff --git a/utests/unittests.cpp b/utests/unittests.cpp index 82af360..cc8ece4 100644 --- a/utests/unittests.cpp +++ b/utests/unittests.cpp @@ -212,6 +212,9 @@ TEST_CASE("contains") REQUIRE(!conjure_enum::contains(static_cast(100))); REQUIRE(conjure_enum::contains("component::path"sv)); REQUIRE(conjure_enum::contains("path"sv)); + REQUIRE(conjure_enum::contains()); + REQUIRE(conjure_enum::contains()); // alias + REQUIRE(conjure_enum::contains()); } //----------------------------------------------------------------------------------------- @@ -304,6 +307,19 @@ TEST_CASE("enum_to_int") REQUIRE(conjure_enum::enum_to_underlying(password) == 4); } +//----------------------------------------------------------------------------------------- +TEST_CASE("index") +{ + REQUIRE(conjure_enum::index(component::scheme).value() == 0); + REQUIRE(conjure_enum::index(component::password).value() == 4); + REQUIRE(conjure_enum::index(component::query).value() == 8); + REQUIRE(conjure_enum::index(component(100)).value_or(100) == 100); + REQUIRE(conjure_enum::index().value() == 0); + REQUIRE(conjure_enum::index().value() == 4); + REQUIRE(conjure_enum::index().value() == 8); + REQUIRE(conjure_enum::index().value_or(100) == 100); +} + //----------------------------------------------------------------------------------------- TEST_CASE("ostream<<") { From 1e30ae19786ccf38debfbdbb593c298c2b4be898 Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 1 Aug 2024 00:57:11 +0000 Subject: [PATCH 006/235] updated --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 799e83c..8fa6cd0 100644 --- a/README.md +++ b/README.md @@ -408,7 +408,8 @@ static constexpr std::optional index(T value); template static constexpr std::optional index(); ``` -Returns the index (position in 0 based array of values) of the supplied enum value `std::optional`. Empty if value was not valid. Use `std::optional::value_or()` to set an error value +Returns the index (position in 0 based array of values) of the supplied enum value as an `std::optional`. +Empty if value was not valid. Use `std::optional::value_or()` to set an error value and avoid throwing an exception. ```c++ std::cout << conjure_enum::index(component::password).value() << '\n'; From d69e67b0c623439e922625f26b546a683ebcd6af Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 1 Aug 2024 04:34:16 +0000 Subject: [PATCH 007/235] updated --- README.md | 109 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 96 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 8fa6cd0..a20ba87 100644 --- a/README.md +++ b/README.md @@ -1453,8 +1453,6 @@ int main(void) { for(const auto& [a, b] : conjure_enum::entries) std::cout << conjure_enum::enum_to_int(a) << ' ' << b << '\n'; - for(const auto& a : conjure_enum::names) - std::cout << a << '\n'; std::cout << static_cast(conjure_enum::string_to_enum("component::path").value()) << '\n'; std::cout << conjure_enum::get_enum_min_value() << '/' << conjure_enum::get_enum_max_value() << '\n'; return 0; @@ -1473,16 +1471,6 @@ $ ./statictest 7 component::path 8 component::query 9 component::fragment -component::scheme -component::authority -component::userinfo -component::user -component::password -component::host -component::port -component::path -component::query -component::fragment 7 0/9 $ @@ -1581,7 +1569,102 @@ would run the script from the `conjure_enum` directory as follows: ```bash ClangBuildAnalyzerLoc=~/prog/ClangBuildAnalyzer/build ArtifactLoc=build_clang examples/cbenchmark.sh ``` -The results will be printed to the screen. +The results will be printed to the screen. For example: +
shell output +

+

+Processing all files and saving to 'cbenchmark.dat'...
+  done in 0.0s. Run 'ClangBuildAnalyzer --analyze cbenchmark.dat' to analyze it.
+Analyzing build trace from 'cbenchmark.dat'...
+**** Time summary:
+Compilation (2 times):
+  Parsing (frontend):            0.7 s
+  Codegen & opts (backend):      0.0 s
+
+**** Files that took longest to parse (compiler frontend):
+   662 ms: build_clang/CMakeFiles/cbenchmark.dir/examples/cbenchmark.cpp.o
+
+**** Files that took longest to codegen (compiler backend):
+    18 ms: build_clang/CMakeFiles/cbenchmark.dir/examples/cbenchmark.cpp.o
+
+**** Templates that took longest to instantiate:
+   290 ms: FIX8::conjure_enum (1 times, avg 290 ms)
+   140 ms: FIX8::conjure_enum::_entries<0UL, 1UL, 2UL, 3UL, 4UL, 5UL... (1 times, avg 140 ms)
+    82 ms: FIX8::conjure_enum::_values<0UL, 1UL, 2UL, 3UL, 4UL, 5UL,... (1 times, avg 82 ms)
+     8 ms: FIX8::conjure_enum::_sorted_entries (1 times, avg 8 ms)
+     7 ms: std::reverse_iterator (1 times, avg 7 ms)
+     6 ms: std::sort> *, boo... (1 times, avg 6 ms)
+     6 ms: std::__sort> *, _... (1 times, avg 6 ms)
+     6 ms: std::reverse_iterator (1 times, avg 6 ms)
+     5 ms: std::unordered_map (1 times, avg 5 ms)
+     5 ms: std::__introsort_loop>, 47> (1 times, avg 3 ms)
+     3 ms: std::_Hashtable, std::allocator::enum_to_string (1 times, avg 3 ms)
+     3 ms: std::tuple, char, std::basic_string_vie... (1 times, avg 3 ms)
+     2 ms: std::__unguarded_partition_pivot> (1 times, avg 2 ms)
+     2 ms: std::tuple>::tuple::_enum_name> *... (1 times, avg 2 ms)
+     2 ms: std::__partial_sort::_enum_name, char, std::basic_string_vie... (1 times, avg 2 ms)
+     2 ms: FIX8::conjure_enum::_enum_name::_enum_name::_enum_name::_enum_name::_enum_name>... (1 times, avg 2 ms)
+
+**** Template sets that took longest to instantiate:
+   290 ms: FIX8::conjure_enum<$> (1 times, avg 290 ms)
+   140 ms: FIX8::conjure_enum<$>::_entries<$> (1 times, avg 140 ms)
+    82 ms: FIX8::conjure_enum<$>::_values<$> (1 times, avg 82 ms)
+    78 ms: FIX8::conjure_enum<$>::_enum_name<$> (47 times, avg 1 ms)
+    55 ms: FIX8::conjure_enum<$>::_is_valid<$> (72 times, avg 0 ms)
+    38 ms: FIX8::conjure_enum<$>::_get_name<$> (47 times, avg 0 ms)
+    15 ms: std::tuple<$>::tuple<$> (20 times, avg 0 ms)
+    13 ms: std::reverse_iterator<$> (2 times, avg 6 ms)
+     8 ms: FIX8::conjure_enum<$>::_sorted_entries (1 times, avg 8 ms)
+     7 ms: std::basic_string<$> (5 times, avg 1 ms)
+     6 ms: std::sort<$> (1 times, avg 6 ms)
+     6 ms: std::__sort<$> (1 times, avg 6 ms)
+     5 ms: std::tuple<$> (2 times, avg 2 ms)
+     5 ms: std::_Hashtable<$> (2 times, avg 2 ms)
+     5 ms: std::unordered_map<$> (1 times, avg 5 ms)
+     5 ms: std::__introsort_loop<$> (1 times, avg 5 ms)
+     4 ms: std::array<$> (2 times, avg 2 ms)
+     4 ms: std::basic_string<$>::_M_construct<$> (4 times, avg 1 ms)
+     3 ms: FIX8::conjure_enum<$>::enum_to_string (1 times, avg 3 ms)
+     3 ms: std::__and_<$> (4 times, avg 0 ms)
+     2 ms: std::__unguarded_partition_pivot<$> (1 times, avg 2 ms)
+     2 ms: std::__move_median_to_first<$> (1 times, avg 2 ms)
+     2 ms: std::iter_swap<$> (1 times, avg 2 ms)
+     2 ms: std::__partial_sort<$> (1 times, avg 2 ms)
+     2 ms: std::copy<$> (3 times, avg 0 ms)
+     2 ms: std::__heap_select<$> (1 times, avg 2 ms)
+     2 ms: std::_Tuple_impl<$> (2 times, avg 1 ms)
+     2 ms: std::__make_heap<$> (1 times, avg 2 ms)
+     1 ms: std::optional<$> (1 times, avg 1 ms)
+     1 ms: std::to_array<$> (1 times, avg 1 ms)
+
+**** Functions that took longest to compile:
+     2 ms: test_conjure_enum(std::errc) (/home/davidd/prog/conjure_enum_tclass/examples/cbenchmark.cpp)
+
+**** Function sets that took longest to compile / optimize:
+
+**** Expensive headers:
+181 ms: /home/davidd/prog/conjure_enum_tclass/include/fix8/conjure_enum.hpp (included 1 times, avg 181 ms), included via:
+  1x: 
+
+173 ms: /usr/include/c++/14/system_error (included 1 times, avg 173 ms), included via:
+  1x: 
+
+  done in 0.0s.
+

--- # 8. Compiler support From 84957e53758b0baf0e9845c482c47ea352ab6e5d Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 1 Aug 2024 04:35:04 +0000 Subject: [PATCH 008/235] updated --- README.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a20ba87..9976d75 100644 --- a/README.md +++ b/README.md @@ -1570,10 +1570,9 @@ would run the script from the `conjure_enum` directory as follows: ClangBuildAnalyzerLoc=~/prog/ClangBuildAnalyzer/build ArtifactLoc=build_clang examples/cbenchmark.sh ``` The results will be printed to the screen. For example: -
shell output +
output

-

-Processing all files and saving to 'cbenchmark.dat'...
+
Processing all files and saving to 'cbenchmark.dat'...
   done in 0.0s. Run 'ClangBuildAnalyzer --analyze cbenchmark.dat' to analyze it.
 Analyzing build trace from 'cbenchmark.dat'...
 **** Time summary:
@@ -1663,8 +1662,7 @@ Compilation (2 times):
 173 ms: /usr/include/c++/14/system_error (included 1 times, avg 173 ms), included via:
   1x: 
 
-  done in 0.0s.
-

+ done in 0.0s.

--- # 8. Compiler support From df4056377dffdd643204966eebb6569fbd373507 Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 1 Aug 2024 04:37:17 +0000 Subject: [PATCH 009/235] updated --- README.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9976d75..c00aec0 100644 --- a/README.md +++ b/README.md @@ -1453,6 +1453,8 @@ int main(void) { for(const auto& [a, b] : conjure_enum::entries) std::cout << conjure_enum::enum_to_int(a) << ' ' << b << '\n'; + for(const auto& a : conjure_enum::names) + std::cout << a << '\n'; std::cout << static_cast(conjure_enum::string_to_enum("component::path").value()) << '\n'; std::cout << conjure_enum::get_enum_min_value() << '/' << conjure_enum::get_enum_max_value() << '\n'; return 0; @@ -1471,6 +1473,16 @@ $ ./statictest 7 component::path 8 component::query 9 component::fragment +component::scheme +component::authority +component::userinfo +component::user +component::password +component::host +component::port +component::path +component::query +component::fragment 7 0/9 $ @@ -1572,7 +1584,8 @@ ClangBuildAnalyzerLoc=~/prog/ClangBuildAnalyzer/build ArtifactLoc=build_clang ex The results will be printed to the screen. For example:
output

-

Processing all files and saving to 'cbenchmark.dat'...
+```CSV
+Processing all files and saving to 'cbenchmark.dat'...
   done in 0.0s. Run 'ClangBuildAnalyzer --analyze cbenchmark.dat' to analyze it.
 Analyzing build trace from 'cbenchmark.dat'...
 **** Time summary:
@@ -1662,7 +1675,9 @@ Compilation (2 times):
 173 ms: /usr/include/c++/14/system_error (included 1 times, avg 173 ms), included via:
   1x: 
 
-  done in 0.0s.

+ done in 0.0s. +``` +

--- # 8. Compiler support From 493fd64e0d97a31b1039c175918668411715bcb5 Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 1 Aug 2024 04:37:53 +0000 Subject: [PATCH 010/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c00aec0..3933006 100644 --- a/README.md +++ b/README.md @@ -1677,7 +1677,7 @@ Compilation (2 times): done in 0.0s. ``` -

+

--- # 8. Compiler support From 72d440182ce9991c06d8408641f2102244c4e501 Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 1 Aug 2024 04:38:43 +0000 Subject: [PATCH 011/235] updated --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 3933006..ac0f241 100644 --- a/README.md +++ b/README.md @@ -1584,6 +1584,7 @@ ClangBuildAnalyzerLoc=~/prog/ClangBuildAnalyzer/build ArtifactLoc=build_clang ex The results will be printed to the screen. For example:
output

+ ```CSV Processing all files and saving to 'cbenchmark.dat'... done in 0.0s. Run 'ClangBuildAnalyzer --analyze cbenchmark.dat' to analyze it. @@ -1677,6 +1678,7 @@ Compilation (2 times): done in 0.0s. ``` +

--- From 45193a9970ac392e4680905caea815d86366d0fa Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 1 Aug 2024 04:46:38 +0000 Subject: [PATCH 012/235] updated --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ac0f241..5f8a3bc 100644 --- a/README.md +++ b/README.md @@ -70,8 +70,8 @@ For the latest cutting edge changes, see the [dev branch](https://github.com/fix ## b) Embracing C++20 -`conjure_enum`[^1] takes full advantage of recently added C++20 features. We've leveraged the convenience of `std::source_location` and -unlocked the potential of `constexpr` algorithms and concepts. +`conjure_enum`[^1] takes full advantage of recently added C++20 features. We've leveraged the convenience of [`std::source_location`](https://en.cppreference.com/w/cpp/utility/source_location) and +unlocked the potential of `constexpr` algorithms (`__cpp_lib_constexpr_algorithms`) and [concepts](https://en.cppreference.com/w/cpp/language/constraints). ## c) Key Benefits From 2432273971d7040be6b3652eeef8ff49f3142a61 Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 1 Aug 2024 04:50:31 +0000 Subject: [PATCH 013/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5f8a3bc..7cbf904 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ For the latest cutting edge changes, see the [dev branch](https://github.com/fix ## b) Embracing C++20 `conjure_enum`[^1] takes full advantage of recently added C++20 features. We've leveraged the convenience of [`std::source_location`](https://en.cppreference.com/w/cpp/utility/source_location) and -unlocked the potential of `constexpr` algorithms (`__cpp_lib_constexpr_algorithms`) and [concepts](https://en.cppreference.com/w/cpp/language/constraints). +unlocked the potential of [`constexpr` algorithms](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0202r3.html) and [concepts](https://en.cppreference.com/w/cpp/language/constraints). ## c) Key Benefits From 41aae76e4fcdb744921498619bee30f0604fa043 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sat, 3 Aug 2024 05:34:05 +0000 Subject: [PATCH 014/235] updated --- README.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 7cbf904..983c307 100644 --- a/README.md +++ b/README.md @@ -239,7 +239,7 @@ _output_ ```CSV 10 ``` -## g) `names` +## g) `names` ![](assets/notminimalred.svg) ```c++ static constexpr std::array names; ``` @@ -443,7 +443,7 @@ true false true ``` -## o) `for_each`, `for_each_n` +## o) `for_each`, `for_each_n` ![](assets/notminimalred.svg) ```c++ template requires std::invocable @@ -547,7 +547,7 @@ _output_ ```CSV 160 ``` -## p) `dispatch` +## p) `dispatch` ![](assets/notminimalred.svg) ```c++ template static constexpr bool tuple_comp(const std::tuple& pl, const std::tuple& pr); @@ -734,7 +734,7 @@ true false false ``` -## w) `iterators` +## w) `iterators` ![](assets/notminimalred.svg) ```c++ static constexpr auto cbegin(); static constexpr auto cend(); @@ -784,7 +784,7 @@ _output_ 8 9 ``` -## y) `front, back` +## y) `front, back` ![](assets/notminimalred.svg) ```c++ static constexpr auto front(); static constexpr auto back(); @@ -1423,10 +1423,14 @@ Static structures and API calls that will be excluded are: scoped_entries unscoped_entries rev_scoped_entries +names unscoped_names remove_scope add_scope unscoped_string_to_enum +for_each,for_each_n +dispatch +iterators enum_to_string //noscope option not available ``` These are marked ![](assets/notminimalred.svg) in the API documentation above. @@ -1453,8 +1457,6 @@ int main(void) { for(const auto& [a, b] : conjure_enum::entries) std::cout << conjure_enum::enum_to_int(a) << ' ' << b << '\n'; - for(const auto& a : conjure_enum::names) - std::cout << a << '\n'; std::cout << static_cast(conjure_enum::string_to_enum("component::path").value()) << '\n'; std::cout << conjure_enum::get_enum_min_value() << '/' << conjure_enum::get_enum_max_value() << '\n'; return 0; From debf00871cd715555ac697d0d47d1eeed7c430f1 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sat, 3 Aug 2024 05:36:48 +0000 Subject: [PATCH 015/235] updated --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 983c307..097d529 100644 --- a/README.md +++ b/README.md @@ -761,7 +761,7 @@ _output_ 8 numbers::eight 9 numbers::nine ``` -## x) `iterator_adaptor` +## x) `iterator_adaptor` ![](assets/notminimalred.svg) ```c++ template struct iterator_adaptor; @@ -801,7 +801,7 @@ _output_ 0 numbers::zero 9 numbers::nine ``` -## z) `ostream_enum_operator` +## z) `ostream_enum_operator` ![](assets/notminimalred.svg) ```c++ template, valid_enum T> constexpr std::basic_ostream& operator<<(std::basic_ostream& os, T value); From 120d0e1d8f8205b0ffff44f6cdefcd094fca6248 Mon Sep 17 00:00:00 2001 From: David Dight Date: Tue, 6 Aug 2024 05:34:18 +1000 Subject: [PATCH 016/235] updated --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 097d529..59c1696 100644 --- a/README.md +++ b/README.md @@ -864,6 +864,12 @@ for the bit positions (and names). > [!WARNING] > Your enum _must_ be continuous. The last value must be less than the count of enumerations. > We decided on this restriction for both simplicity and practicality - bitsets only really make sense when represented in this manner. +> [!INFO] +> You must include +```C++ +#include +#include +``` ## a) Creating an `enum_bitset` ```c++ From 5a3735eb532915bf72d708c0a86ef9aa9c9969e1 Mon Sep 17 00:00:00 2001 From: David Dight Date: Tue, 6 Aug 2024 05:35:27 +1000 Subject: [PATCH 017/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 59c1696..a50d7dc 100644 --- a/README.md +++ b/README.md @@ -864,7 +864,7 @@ for the bit positions (and names). > [!WARNING] > Your enum _must_ be continuous. The last value must be less than the count of enumerations. > We decided on this restriction for both simplicity and practicality - bitsets only really make sense when represented in this manner. -> [!INFO] +> [!IMPORTANT] > You must include ```C++ #include From d7ba719020960fea7011c1efb9c2721b605d0e66 Mon Sep 17 00:00:00 2001 From: David Dight Date: Tue, 6 Aug 2024 05:35:46 +1000 Subject: [PATCH 018/235] updated --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a50d7dc..e43e8ff 100644 --- a/README.md +++ b/README.md @@ -864,6 +864,7 @@ for the bit positions (and names). > [!WARNING] > Your enum _must_ be continuous. The last value must be less than the count of enumerations. > We decided on this restriction for both simplicity and practicality - bitsets only really make sense when represented in this manner. + > [!IMPORTANT] > You must include ```C++ From 4af7a62c1855d4d215bd3b8f6c963380d21e8ba4 Mon Sep 17 00:00:00 2001 From: David Dight Date: Tue, 6 Aug 2024 05:36:41 +1000 Subject: [PATCH 019/235] updated --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index e43e8ff..069afc6 100644 --- a/README.md +++ b/README.md @@ -1161,6 +1161,13 @@ not found: 5 # 5. API and Examples using `conjure_type` `conjure_type` is a general purpose class allowing you to extract a string representation of any typename. The string will be stored statically by the compiler, so you can use the statically generated value `name` to obtain your type. +> [!IMPORTANT] +> You must include +```C++ +#include +#include +``` + ```c++ template class conjure_type; From f7a56dcf5e49f134e6200aed3913f61f0bbedf55 Mon Sep 17 00:00:00 2001 From: David Dight Date: Tue, 6 Aug 2024 05:37:10 +1000 Subject: [PATCH 020/235] updated --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 069afc6..b11f41e 100644 --- a/README.md +++ b/README.md @@ -1163,10 +1163,10 @@ not found: 5 The string will be stored statically by the compiler, so you can use the statically generated value `name` to obtain your type. > [!IMPORTANT] > You must include -```C++ -#include -#include -``` +> ```C++ +> #include +> #include +> ``` ```c++ template From 17c8f07bb8308e34ccfde372a86020381ac28010 Mon Sep 17 00:00:00 2001 From: David Dight Date: Tue, 6 Aug 2024 05:37:52 +1000 Subject: [PATCH 021/235] updated --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b11f41e..e80e397 100644 --- a/README.md +++ b/README.md @@ -867,10 +867,10 @@ for the bit positions (and names). > [!IMPORTANT] > You must include -```C++ -#include -#include -``` +> ```C++ +> #include +> #include +> ``` ## a) Creating an `enum_bitset` ```c++ From 13d4c2a062b72d1c59fea7a7f76d1aa8043ee7b9 Mon Sep 17 00:00:00 2001 From: David Dight Date: Tue, 6 Aug 2024 05:39:18 +1000 Subject: [PATCH 022/235] updated --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e80e397..3ed2fa1 100644 --- a/README.md +++ b/README.md @@ -1168,12 +1168,13 @@ The string will be stored statically by the compiler, so you can use the statica > #include > ``` +## `name` +This static member is generated for your type. It is a `fixed_string` but has a built-in `std::string_view` operator. ```c++ template class conjure_type; static constexpr fixed_string name; ``` -This static member is generated for your type. It is a `fixed_string` but has a built-in `std::string_view` operator. ```c++ class foo; From 4d8925fc6afdf8f9d951cb2282bee8f100cec97a Mon Sep 17 00:00:00 2001 From: David Dight Date: Tue, 6 Aug 2024 07:23:51 +1000 Subject: [PATCH 023/235] pre-rel 1.0.2b --- examples/example.cpp | 2 + examples/srcloctest.cpp | 6 +- examples/statictest.cpp | 2 - include/fix8/conjure_enum.hpp | 534 +-------------------------- include/fix8/conjure_enum_bitset.hpp | 304 +++++++++++++++ include/fix8/conjure_enum_ext.hpp | 239 ++++++++++++ include/fix8/conjure_type.hpp | 112 ++++++ utests/edgetests.cpp | 1 + utests/unittests.cpp | 2 + 9 files changed, 674 insertions(+), 528 deletions(-) create mode 100644 include/fix8/conjure_enum_bitset.hpp create mode 100644 include/fix8/conjure_enum_ext.hpp create mode 100644 include/fix8/conjure_type.hpp diff --git a/examples/example.cpp b/examples/example.cpp index 9cf0ed2..d9fa14f 100644 --- a/examples/example.cpp +++ b/examples/example.cpp @@ -40,6 +40,8 @@ #endif #include +#include +#include //----------------------------------------------------------------------------------------- using namespace std::literals::string_view_literals; diff --git a/examples/srcloctest.cpp b/examples/srcloctest.cpp index 566831e..efee3dd 100644 --- a/examples/srcloctest.cpp +++ b/examples/srcloctest.cpp @@ -152,9 +152,9 @@ int main(int argc, char **argv) }; bool mkd{}, cpl{true}, hlp{}; - std::map opts { {"-m",mkd},{"-c",cpl},{"-h",hlp} }; - for (int ii{1}; ii < argc; ++ii) - if (auto result{opts.find(std::string_view(argv[ii]))}; result != opts.cend()) + const std::map opts { {"-m",mkd},{"-c",cpl},{"-h",hlp} }; + for (const std::vector args{argv + 1, argv + argc}; const auto pp : args) + if (auto result{opts.find(pp)}; result != opts.cend()) result->second ^= true; if (hlp) { diff --git a/examples/statictest.cpp b/examples/statictest.cpp index e3afa6b..7956a1f 100644 --- a/examples/statictest.cpp +++ b/examples/statictest.cpp @@ -44,8 +44,6 @@ int main(void) { for(const auto& [a, b] : conjure_enum::entries) std::cout << conjure_enum::enum_to_int(a) << ' ' << b << '\n'; - for(const auto& a : conjure_enum::names) - std::cout << a << '\n'; std::cout << static_cast(conjure_enum::string_to_enum("component::path").value()) << '\n'; std::cout << conjure_enum::get_enum_min_value() << '/' << conjure_enum::get_enum_max_value() << '\n'; return 0; diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 5ca96ee..f769f1f 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -31,6 +31,8 @@ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. //---------------------------------------------------------------------------------------- +// conjure_enum +//---------------------------------------------------------------------------------------- #ifndef FIX8_CONJURE_ENUM_HPP_ #define FIX8_CONJURE_ENUM_HPP_ @@ -45,12 +47,10 @@ #include #include #include -#include -#include -#include -#include -#include -#include +#if not defined FIX8_CONJURE_ENUM_MINIMAL +# include +#endif +//#include #include //----------------------------------------------------------------------------------------- @@ -174,7 +174,8 @@ template class conjure_enum : public static_only { static constexpr int enum_min_value{enum_range::min}, enum_max_value{enum_range::max}; - static_assert(enum_max_value > enum_min_value, "FIX8_CONJURE_ENUM_MAX_VALUE must be greater than FIX8_CONJURE_ENUM_MIN_VALUE"); + static_assert(enum_max_value > enum_min_value, + "FIX8_CONJURE_ENUM_MAX_VALUE (or enum_range::max) must be greater than FIX8_CONJURE_ENUM_MIN_VALUE (or enum_range::min) "); public: using enum_tuple = std::tuple; @@ -197,12 +198,6 @@ class conjure_enum : public static_only return std::array{{{ values[I], _enum_name_v}...}}; } - template - static constexpr auto _names(std::index_sequence) noexcept - { - return std::array{{{ _enum_name_v}...}}; - } - static constexpr auto _sorted_entries() noexcept { auto tmp { entries }; @@ -210,45 +205,6 @@ class conjure_enum : public static_only return tmp; } -#if not defined FIX8_CONJURE_ENUM_MINIMAL - template - static constexpr auto _unscoped_entries(std::index_sequence) noexcept - { - std::array tmp{{{ values[I], _remove_scope(_enum_name_v)}...}}; - std::sort(tmp.begin(), tmp.end(), _tuple_comp_rev); - return tmp; - } - - static constexpr std::string_view _remove_scope(std::string_view what) noexcept - { - if (const auto lc { what.find_last_of(':') }; lc != std::string_view::npos) - return what.substr(lc + 1); - return what; - } - - template - static constexpr auto _scoped_entries(std::index_sequence) noexcept - { - std::array tmp{{{ _remove_scope(_enum_name_v), _enum_name_v}...}}; - std::sort(tmp.begin(), tmp.end(), _scoped_comp); - return tmp; - } - - template - static constexpr auto _rev_scoped_entries(std::index_sequence) noexcept - { - std::array tmp{{{ _enum_name_v, _remove_scope(_enum_name_v)}...}}; - std::sort(tmp.begin(), tmp.end(), _scoped_comp); - return tmp; - } - - template - static constexpr auto _unscoped_names(std::index_sequence) noexcept - { - return std::array{{{ _remove_scope(_enum_name_v)}...}}; - } -#endif - template static constexpr bool _is_valid() noexcept { @@ -314,18 +270,6 @@ class conjure_enum : public static_only return {}; } -#if not defined FIX8_CONJURE_ENUM_MINIMAL - static constexpr std::string_view _process_scope([[maybe_unused]] const auto& entr, std::string_view what) noexcept - { - if constexpr (is_scoped()) - if (const auto result { std::equal_range(entr.cbegin(), - entr.cend(), scoped_tuple(what, std::string_view()), _scoped_comp) }; - result.first != result.second) - return std::get<1>(*result.first); - return what; - } -#endif - /// comparators static constexpr bool _value_comp(const T& pl, const T& pr) noexcept { @@ -339,12 +283,6 @@ class conjure_enum : public static_only { return std::get(pl) < std::get(pr); } -#if not defined FIX8_CONJURE_ENUM_MINIMAL - static constexpr bool _scoped_comp(const scoped_tuple& pl, const scoped_tuple& pr) noexcept - { - return std::get<0>(pl) < std::get<0>(pr); - } -#endif public: static consteval const char *tpeek() noexcept { return std::source_location::current().function_name(); } @@ -397,25 +335,6 @@ class conjure_enum : public static_only else return false; } -#if not defined FIX8_CONJURE_ENUM_MINIMAL - static constexpr std::string_view remove_scope(std::string_view what) noexcept - { - return _process_scope(rev_scoped_entries, what); - } - - static constexpr std::string_view add_scope(std::string_view what) noexcept - { - return _process_scope(scoped_entries, what); - } -#endif - - // iterators - static constexpr auto cbegin() noexcept { return entries.cbegin(); } - static constexpr auto cend() noexcept { return entries.cend(); } - static constexpr auto crbegin() noexcept { return entries.crbegin(); } - static constexpr auto crend() noexcept { return entries.crend(); } - static constexpr auto front() noexcept { return *cbegin(); } - static constexpr auto back() noexcept { return *std::prev(cend()); } // enum <==> int static constexpr int enum_to_int(T value) noexcept @@ -483,452 +402,21 @@ class conjure_enum : public static_only return std::get(*result.first); return {}; } -#if not defined FIX8_CONJURE_ENUM_MINIMAL - static constexpr std::optional unscoped_string_to_enum(std::string_view str) noexcept - { - if (const auto result { std::equal_range(unscoped_entries.cbegin(), unscoped_entries.cend(), enum_tuple(T{}, str), _tuple_comp_rev) }; - result.first != result.second) - return std::get(*result.first); - return {}; - } -#endif - - /// for_each, for_each_n - template - requires std::invocable - [[maybe_unused]] static constexpr auto for_each(Fn&& func, Args&&... args) noexcept - { - return for_each_n(static_cast(count()), std::forward(func), std::forward(args)...); - } - - template // specialisation for member function with object - requires std::invocable - [[maybe_unused]] static constexpr auto for_each(Fn&& func, C *obj, Args&&... args) noexcept - { - return for_each(std::bind(std::forward(func), obj, std::placeholders::_1, std::forward(args)...)); - } - - template - requires std::invocable - [[maybe_unused]] static constexpr auto for_each_n(int n, Fn&& func, Args&&... args) noexcept - { - for (int ii{}; const auto ev : conjure_enum::values) - { - if (ii++ >= n) - break; - std::invoke(std::forward(func), ev, std::forward(args)...); - } - return std::bind(std::forward(func), std::placeholders::_1, std::forward(args)...); - } - - template // specialisation for member function with object - requires std::invocable - [[maybe_unused]] static constexpr auto for_each_n(int n, Fn&& func, C *obj, Args&&... args) noexcept - { - return for_each_n(n, std::bind(std::forward(func), obj, std::placeholders::_1, std::forward(args)...)); - } - - // dispatch - template - static constexpr bool tuple_comp(const std::tuple& pl, const std::tuple& pr) noexcept - { - return static_cast(std::get(pl)) < static_cast(std::get(pr)); - } - - template // with not found value(nval) for return - requires std::invocable - [[maybe_unused]] static constexpr R dispatch(T ev, R nval, const std::array, I>& disp, Args&&... args) noexcept - { - const auto result { std::equal_range(disp.cbegin(), disp.cend(), std::make_tuple(ev, Fn()), tuple_comp) }; - return result.first != result.second ? std::invoke(std::get(*result.first), ev, std::forward(args)...) : nval; - } - - template // specialisation for member function with not found value(nval) for return - requires std::invocable - [[maybe_unused]] static constexpr R dispatch(T ev, R nval, const std::array, I>& disp, C *obj, Args&&... args) noexcept - { - const auto result { std::equal_range(disp.cbegin(), disp.cend(), std::make_tuple(ev, Fn()), tuple_comp) }; - return result.first != result.second ? std::invoke(std::get(*result.first), obj, ev, std::forward(args)...) : nval; - } - - template // void func with not found call to last element - requires (std::invocable && I > 0) - static constexpr void dispatch(T ev, const std::array, I>& disp, Args&&... args) noexcept - { - const auto result { std::equal_range(disp.cbegin(), std::prev(disp.cend()), std::make_tuple(ev, Fn()), tuple_comp) }; - return result.first != result.second ? std::invoke(std::get(*result.first), ev, std::forward(args)...) - : std::invoke(std::get(*std::prev(disp.cend())), ev, std::forward(args)...); - } - - template // specialisation for void member function with not found call to last element - requires (std::invocable && I > 0) - static constexpr void dispatch(T ev, const std::array, I>& disp, C *obj, Args&&... args) noexcept - { - const auto result { std::equal_range(disp.cbegin(), std::prev(disp.cend()), std::make_tuple(ev, Fn()), tuple_comp) }; - return result.first != result.second ? std::invoke(std::get(*result.first), obj, ev, std::forward(args)...) - : std::invoke(std::get(*std::prev(disp.cend())), obj, ev, std::forward(args)...); - } // public constexpr data structures static constexpr auto values { _values(std::make_index_sequence()) }; static constexpr auto entries { _entries(std::make_index_sequence()) }; - static constexpr auto names { _names(std::make_index_sequence()) }; static constexpr auto sorted_entries { _sorted_entries() }; -#if not defined FIX8_CONJURE_ENUM_MINIMAL - static constexpr auto scoped_entries { _scoped_entries(std::make_index_sequence()) }; - static constexpr auto unscoped_entries { _unscoped_entries(std::make_index_sequence()) }; - static constexpr auto rev_scoped_entries { _rev_scoped_entries(std::make_index_sequence()) }; - static constexpr auto unscoped_names { _unscoped_names(std::make_index_sequence()) }; -#endif // misc static constexpr int get_enum_min_value() noexcept { return enum_min_value; } static constexpr int get_enum_max_value() noexcept { return enum_max_value; } -}; -//----------------------------------------------------------------------------------------- -// allow range based for -template -struct iterator_adaptor -{ - constexpr auto begin() noexcept { return conjure_enum::entries.cbegin(); } - constexpr auto end() noexcept { return conjure_enum::entries.cend(); } -}; - -//----------------------------------------------------------------------------------------- -// ostream& operator<< for any enum; add the following before using: -// using ostream_enum_operator::operator<<; -//----------------------------------------------------------------------------------------- -namespace ostream_enum_operator -{ - template, valid_enum T> - constexpr std::basic_ostream& operator<<(std::basic_ostream& os, T value) noexcept - { - if (conjure_enum::contains(value)) - return os << conjure_enum::enum_to_string(value); - return os << conjure_enum::enum_to_underlying(value); - } -} - -//----------------------------------------------------------------------------------------- -//----------------------------------------------------------------------------------------- -template -concept valid_bitset_enum = valid_enum and requires(T) -{ - requires static_cast(conjure_enum::values.back()) < conjure_enum::count(); -}; - -//----------------------------------------------------------------------------------------- -// bitset based on supplied enum -// Note: your enum sequence must be continuous with the last enum value < count of enumerations -//----------------------------------------------------------------------------------------- -template -class enum_bitset -{ - using U = std::underlying_type_t; - static constexpr auto countof { conjure_enum::count() }; - - template - static constexpr U to_underlying() noexcept { return static_cast(val); } // C++23: upgrade to std::to_underlying - static constexpr U to_underlying(T val) noexcept { return static_cast(val); } - static constexpr U all_bits { (1 << countof) - 1 }; - U _present{}; - -public: - explicit constexpr enum_bitset(U bits) noexcept : _present(bits) {} - constexpr enum_bitset(std::string_view from, bool anyscope=false, char sep='|', bool ignore_errors=true) - : _present(factory(from, anyscope, sep, ignore_errors)) {} - - template - constexpr enum_bitset(E... comp) noexcept : _present((0u | ... | (1 << to_underlying(comp)))) {} - - template - constexpr enum_bitset(I... comp) noexcept : _present((0u | ... | (1 << comp))) {} - - constexpr enum_bitset() = default; - constexpr ~enum_bitset() = default; - - constexpr std::size_t count() const noexcept - { return std::popcount(static_cast>(_present)); } // C++23: upgrade to std::bitset when count is constexpr - constexpr std::size_t not_count() const noexcept { return countof - count(); } - constexpr std::size_t size() const noexcept { return countof; } - constexpr U to_ulong() const noexcept { return _present; } - constexpr unsigned long long to_ullong() const noexcept { return _present; } - - constexpr bool operator[](std::size_t pos) const noexcept { return test(pos); } - constexpr bool operator[](T what) const noexcept { return test(what); } - - /// set - constexpr void set(U pos, bool value=true) noexcept { value ? _present |= 1 << pos : _present &= ~(1 << pos); } - constexpr void set(T what, bool value=true) noexcept { set(to_underlying(what), value); } - constexpr void set() noexcept { _present = all_bits; } - - template - constexpr void set() noexcept - { - if constexpr (constexpr auto uu{to_underlying()}; uu < countof) - _present |= 1 << uu; - } - - template - requires (sizeof...(comp) > 1) - constexpr void set() noexcept { (set(),...); } - - template - requires (sizeof...(E) > 1) - constexpr void set(E... comp) noexcept { return (... | (set(comp))); } - - /// flip - template - constexpr void flip() noexcept - { - if constexpr (constexpr auto uu{to_underlying()}; uu < countof) - _present ^= 1 << uu; - } - - constexpr void flip() noexcept { _present = ~_present & all_bits; } - constexpr void flip(U pos) noexcept { _present ^= 1 << pos; } - constexpr void flip(T what) noexcept { flip(to_underlying(what)); } - - /// reset - template - constexpr void reset() noexcept - { - if constexpr (constexpr auto uu{to_underlying()}; uu < countof) - _present &= ~(1 << uu); - } - - constexpr void reset() noexcept { _present = 0; } - constexpr void reset(U pos) noexcept { _present &= ~(1 << pos); } - constexpr void reset(T what) noexcept { reset(to_underlying(what)); } - - template - requires (sizeof...(comp) > 1) - constexpr void reset() noexcept { (reset(),...); } - - template - constexpr void reset(I...comp) noexcept { (reset(comp),...); } - - /// test - constexpr bool test(U pos) const noexcept { return _present & 1 << pos; } - constexpr bool test(T what) const noexcept { return test(to_underlying(what)); } - constexpr bool test() const noexcept { return _present; } - - template - constexpr bool test() const noexcept - { - if constexpr (constexpr auto uu{to_underlying()}; uu < countof) - return test(uu); - else - return false; - } - - template - constexpr bool any_of() const noexcept { return (... || test()); } - - template - constexpr bool any_of(I...comp) const noexcept { return (... || test(comp)); } - - template - constexpr bool any_of(E...comp) const noexcept { return (... || test(comp)); } - - template - constexpr bool all_of() const noexcept { return (... && test()); } - - template - constexpr bool all_of(I...comp) const noexcept { return (... && test(comp)); } - - template - constexpr bool all_of(E...comp) const noexcept { return (... && test(comp)); } - - template - constexpr bool none_of() const noexcept { return (... && !test()); } - - template - constexpr bool none_of(I...comp) const noexcept { return (... && !test(comp)); } - - template - constexpr bool none_of(E...comp) const noexcept { return (... && !test(comp)); } - - constexpr bool any() const noexcept { return count(); } - constexpr bool all() const noexcept { return _present == all_bits; } - constexpr bool none() const noexcept { return !*this; } - - /// operators - constexpr operator bool() const noexcept { return count(); } - constexpr enum_bitset& operator<<=(std::size_t pos) noexcept { _present <<= pos; return *this; } - constexpr enum_bitset& operator>>=(std::size_t pos) noexcept { _present >>= pos; return *this; } - constexpr enum_bitset& operator&=(T other) noexcept { _present &= 1 << to_underlying(other); return *this; } - constexpr enum_bitset& operator|=(T other) noexcept { _present |= 1 << to_underlying(other); return *this; } - constexpr enum_bitset& operator^=(T other) noexcept { _present ^= 1 << to_underlying(other); return *this; } - constexpr enum_bitset& operator&=(U other) noexcept { _present &= other; return *this; } - constexpr enum_bitset& operator|=(U other) noexcept { _present |= other; return *this; } - constexpr enum_bitset& operator^=(U other) noexcept { _present ^= other; return *this; } - - constexpr enum_bitset operator<<(int pos) const noexcept { return enum_bitset(_present << pos); } - constexpr enum_bitset operator>>(int pos) const noexcept { return enum_bitset(_present >> pos); } - constexpr enum_bitset operator&(T other) const noexcept { return enum_bitset(_present & 1 << to_underlying(other)); } - constexpr enum_bitset operator|(T other) const noexcept { return enum_bitset(_present | 1 << to_underlying(other)); } - constexpr enum_bitset operator^(T other) const noexcept { return enum_bitset(_present ^ 1 << to_underlying(other)); } - constexpr enum_bitset operator&(U other) const noexcept { return enum_bitset(_present & other); } - constexpr enum_bitset operator|(U other) const noexcept { return enum_bitset(_present | other); } - constexpr enum_bitset operator^(U other) const noexcept { return enum_bitset(_present ^ other); } - constexpr enum_bitset operator~() const noexcept { return enum_bitset(~_present & all_bits); } - - /// for_each, for_each_n - template - requires std::invocable - [[maybe_unused]] constexpr auto for_each(Fn&& func, Args&&... args) noexcept - { - return for_each_n(static_cast(countof), std::forward(func), std::forward(args)...); - } - - template // specialisation for member function with object - requires std::invocable - [[maybe_unused]] constexpr auto for_each(Fn&& func, C *obj, Args&&... args) noexcept - { - return for_each(std::bind(std::forward(func), obj, std::placeholders::_1, std::forward(args)...)); - } - - template - requires std::invocable - [[maybe_unused]] constexpr auto for_each_n(int n, Fn&& func, Args&&... args) noexcept - { - for (int ii{}, jj{}; ii < static_cast(countof) && jj < n; ++ii) - if (const auto ev{conjure_enum::values[ii]}; test(ev)) - std::invoke(std::forward(func), ev, std::forward(args)...), ++jj; - return std::bind(std::forward(func), std::placeholders::_1, std::forward(args)...); - } - - template // specialisation for member function with object - requires std::invocable - [[maybe_unused]] constexpr auto for_each_n(int n, Fn&& func, C *obj, Args&&... args) noexcept - { - return for_each_n(n, std::bind(std::forward(func), obj, std::placeholders::_1, std::forward(args)...)); - } - - /// create a bitset from custom separated enum string - static constexpr U factory(std::string_view src, bool anyscope, char sep, bool ignore_errors) - { - enum_bitset result; - constexpr auto trim([](std::string_view src) noexcept ->auto - { - const auto bg(src.find_first_not_of(" \t")); - return bg == std::string_view::npos ? src : src.substr(bg, src.find_last_not_of(" \t") - bg + 1); - }); - auto process([anyscope,&result](std::string_view src) noexcept ->auto - { - if (anyscope && !conjure_enum::has_scope(src)) - src = conjure_enum::add_scope(src); - if (auto ev { conjure_enum::string_to_enum(src) }; ev) - { - result |= *ev; - return true; - } - return false; - }); - for (std::string_view::size_type pos{}, fnd{};; pos = fnd + 1) - { - if ((fnd = src.find_first_of(sep, pos)) != std::string_view::npos) - { - if (auto srcp { trim(src.substr(pos, fnd - pos)) }; !process(trim(srcp)) && !ignore_errors) - throw std::invalid_argument(std::string(srcp).c_str()); - continue; - } - if (pos < src.size()) - if (auto srcp { trim(src.substr(pos, src.size() - pos)) }; !process(trim(srcp)) && !ignore_errors) - throw std::invalid_argument(std::string(srcp).c_str()); - break; - } - return result._present; - } - - constexpr std::string to_string(char zero='0', char one='1') const noexcept - { - return std::bitset(_present).to_string(zero, one); - } - - friend constexpr std::ostream& operator<<(std::ostream& os, const enum_bitset& what) noexcept - { - return os << what.to_string(); - } -}; - -template -constexpr enum_bitset operator&(const enum_bitset& lh, const enum_bitset& rh) noexcept - { return lh.operator&(rh.to_ulong()); } -template -constexpr enum_bitset operator|(const enum_bitset& lh, const enum_bitset& rh) noexcept - { return lh.operator|(rh.to_ulong()); } -template -constexpr enum_bitset operator^(const enum_bitset& lh, const enum_bitset& rh) noexcept - { return lh.operator^(rh.to_ulong()); } - -//----------------------------------------------------------------------------------------- -// General purpose class allowing you to extract a string representation of any typename. -// The string will be stored statically by the compiler, so you can use the statically generated value `name` to obtain your type. -//----------------------------------------------------------------------------------------- -template -class conjure_type : public static_only -{ - static constexpr std::string_view _get_name() noexcept - { - constexpr std::string_view from{tpeek()}; -#if defined _MSC_VER - constexpr auto ep { from.rfind(cs::get_spec()) }; - if constexpr (ep == std::string_view::npos) - return {}; - if constexpr (constexpr auto lc { from.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) - { - constexpr auto e1 { from.substr(lc + 1, ep - lc - 2) }; - CHKMSSTR(e1,type_t); - CHKMSSTR(e1,extype_t0); - CHKMSSTR(e1,extype_t1); - CHKMSSTR(e1,extype_t2); - CHKMSSTR(e1,extype_t3); - } - return {}; - } -#else - constexpr auto ep { from.rfind(cs::get_spec()) }; - if constexpr (ep == std::string_view::npos) - return {}; - if constexpr (from[ep + cs::get_spec().size()] == cs::get_spec()) - if (constexpr auto lstr { from.substr(ep + cs::get_spec().size()) }; - lstr.find(cs::get_spec()) != std::string_view::npos) // is anon - if constexpr (constexpr auto lc { lstr.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) - return lstr.substr(cs::get_spec().size() + 2, lc - (cs::get_spec().size() + 2)); // eat "::" - constexpr auto result { from.substr(ep + cs::get_spec().size()) }; - if constexpr (constexpr auto lc { result.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) - return result.substr(0, lc); - return {}; - } - static constexpr auto _type_name() noexcept - { - constexpr auto result { _get_name() }; - return fixed_string(result); - } -#endif - -public: - static consteval const char *tpeek() noexcept { return std::source_location::current().function_name(); } - static constexpr auto name - { -#if defined _MSC_VER - _get_name() -#else - _type_name() -#endif - }; - static constexpr std::string_view as_string_view() noexcept - { -#if defined _MSC_VER - return name; +#if not defined FIX8_CONJURE_ENUM_MINIMAL +#include #else - return name.get(); -#endif - } }; +#endif //----------------------------------------------------------------------------------------- } // FIX8 diff --git a/include/fix8/conjure_enum_bitset.hpp b/include/fix8/conjure_enum_bitset.hpp new file mode 100644 index 0000000..6415803 --- /dev/null +++ b/include/fix8/conjure_enum_bitset.hpp @@ -0,0 +1,304 @@ +//----------------------------------------------------------------------------------------- +// SPDX-License-Identifier: MIT +// SPDX-FileCopyrightText: Copyright (C) 2024 Fix8 Market Technologies Pty Ltd +// SPDX-FileType: SOURCE +// +// conjure_enum (header only) +// by David L. Dight +// see https://github.com/fix8mt/conjure_enum +// +// Lightweight header-only C++20 enum and typename reflection +// +// Parts based on magic_enum +// Copyright (c) 2019 - 2024 Daniil Goncharov . +// +// Licensed under the MIT License . +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is furnished +// to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice (including the next paragraph) +// shall be included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +//---------------------------------------------------------------------------------------- +// enum_bitset +//---------------------------------------------------------------------------------------- +#ifndef FIX8_CONJURE_ENUM_BITSET_HPP_ +#define FIX8_CONJURE_ENUM_BITSET_HPP_ + +//---------------------------------------------------------------------------------------- +#include +#include +#include + +//----------------------------------------------------------------------------------------- +namespace FIX8 { + +//----------------------------------------------------------------------------------------- +template +concept valid_bitset_enum = valid_enum and requires(T) +{ + requires static_cast(conjure_enum::values.back()) < conjure_enum::count(); +}; + +//----------------------------------------------------------------------------------------- +// bitset based on supplied enum +// Note: your enum sequence must be continuous with the last enum value < count of enumerations +//----------------------------------------------------------------------------------------- +template +class enum_bitset +{ + using U = std::underlying_type_t; + static constexpr auto countof { conjure_enum::count() }; + + template + static constexpr U to_underlying() noexcept { return static_cast(val); } // C++23: upgrade to std::to_underlying + static constexpr U to_underlying(T val) noexcept { return static_cast(val); } + static constexpr U all_bits { (1 << countof) - 1 }; + U _present{}; + +public: + explicit constexpr enum_bitset(U bits) noexcept : _present(bits) {} + constexpr enum_bitset(std::string_view from, bool anyscope=false, char sep='|', bool ignore_errors=true) + : _present(factory(from, anyscope, sep, ignore_errors)) {} + + template + constexpr enum_bitset(E... comp) noexcept : _present((0u | ... | (1 << to_underlying(comp)))) {} + + template + constexpr enum_bitset(I... comp) noexcept : _present((0u | ... | (1 << comp))) {} + + constexpr enum_bitset() = default; + constexpr ~enum_bitset() = default; + + constexpr std::size_t count() const noexcept + { return std::popcount(static_cast>(_present)); } // C++23: upgrade to std::bitset when count is constexpr + constexpr std::size_t not_count() const noexcept { return countof - count(); } + constexpr std::size_t size() const noexcept { return countof; } + constexpr U to_ulong() const noexcept { return _present; } + constexpr unsigned long long to_ullong() const noexcept { return _present; } + + constexpr bool operator[](std::size_t pos) const noexcept { return test(pos); } + constexpr bool operator[](T what) const noexcept { return test(what); } + + /// set + constexpr void set(U pos, bool value=true) noexcept { value ? _present |= 1 << pos : _present &= ~(1 << pos); } + constexpr void set(T what, bool value=true) noexcept { set(to_underlying(what), value); } + constexpr void set() noexcept { _present = all_bits; } + + template + constexpr void set() noexcept + { + if constexpr (constexpr auto uu{to_underlying()}; uu < countof) + _present |= 1 << uu; + } + + template + requires (sizeof...(comp) > 1) + constexpr void set() noexcept { (set(),...); } + + template + requires (sizeof...(E) > 1) + constexpr void set(E... comp) noexcept { return (... | (set(comp))); } + + /// flip + template + constexpr void flip() noexcept + { + if constexpr (constexpr auto uu{to_underlying()}; uu < countof) + _present ^= 1 << uu; + } + + constexpr void flip() noexcept { _present = ~_present & all_bits; } + constexpr void flip(U pos) noexcept { _present ^= 1 << pos; } + constexpr void flip(T what) noexcept { flip(to_underlying(what)); } + + /// reset + template + constexpr void reset() noexcept + { + if constexpr (constexpr auto uu{to_underlying()}; uu < countof) + _present &= ~(1 << uu); + } + + constexpr void reset() noexcept { _present = 0; } + constexpr void reset(U pos) noexcept { _present &= ~(1 << pos); } + constexpr void reset(T what) noexcept { reset(to_underlying(what)); } + + template + requires (sizeof...(comp) > 1) + constexpr void reset() noexcept { (reset(),...); } + + template + constexpr void reset(I...comp) noexcept { (reset(comp),...); } + + /// test + constexpr bool test(U pos) const noexcept { return _present & 1 << pos; } + constexpr bool test(T what) const noexcept { return test(to_underlying(what)); } + constexpr bool test() const noexcept { return _present; } + + template + constexpr bool test() const noexcept + { + if constexpr (constexpr auto uu{to_underlying()}; uu < countof) + return test(uu); + else + return false; + } + + template + constexpr bool any_of() const noexcept { return (... || test()); } + + template + constexpr bool any_of(I...comp) const noexcept { return (... || test(comp)); } + + template + constexpr bool any_of(E...comp) const noexcept { return (... || test(comp)); } + + template + constexpr bool all_of() const noexcept { return (... && test()); } + + template + constexpr bool all_of(I...comp) const noexcept { return (... && test(comp)); } + + template + constexpr bool all_of(E...comp) const noexcept { return (... && test(comp)); } + + template + constexpr bool none_of() const noexcept { return (... && !test()); } + + template + constexpr bool none_of(I...comp) const noexcept { return (... && !test(comp)); } + + template + constexpr bool none_of(E...comp) const noexcept { return (... && !test(comp)); } + + constexpr bool any() const noexcept { return count(); } + constexpr bool all() const noexcept { return _present == all_bits; } + constexpr bool none() const noexcept { return !*this; } + + /// operators + constexpr operator bool() const noexcept { return count(); } + constexpr enum_bitset& operator<<=(std::size_t pos) noexcept { _present <<= pos; return *this; } + constexpr enum_bitset& operator>>=(std::size_t pos) noexcept { _present >>= pos; return *this; } + constexpr enum_bitset& operator&=(T other) noexcept { _present &= 1 << to_underlying(other); return *this; } + constexpr enum_bitset& operator|=(T other) noexcept { _present |= 1 << to_underlying(other); return *this; } + constexpr enum_bitset& operator^=(T other) noexcept { _present ^= 1 << to_underlying(other); return *this; } + constexpr enum_bitset& operator&=(U other) noexcept { _present &= other; return *this; } + constexpr enum_bitset& operator|=(U other) noexcept { _present |= other; return *this; } + constexpr enum_bitset& operator^=(U other) noexcept { _present ^= other; return *this; } + + constexpr enum_bitset operator<<(int pos) const noexcept { return enum_bitset(_present << pos); } + constexpr enum_bitset operator>>(int pos) const noexcept { return enum_bitset(_present >> pos); } + constexpr enum_bitset operator&(T other) const noexcept { return enum_bitset(_present & 1 << to_underlying(other)); } + constexpr enum_bitset operator|(T other) const noexcept { return enum_bitset(_present | 1 << to_underlying(other)); } + constexpr enum_bitset operator^(T other) const noexcept { return enum_bitset(_present ^ 1 << to_underlying(other)); } + constexpr enum_bitset operator&(U other) const noexcept { return enum_bitset(_present & other); } + constexpr enum_bitset operator|(U other) const noexcept { return enum_bitset(_present | other); } + constexpr enum_bitset operator^(U other) const noexcept { return enum_bitset(_present ^ other); } + constexpr enum_bitset operator~() const noexcept { return enum_bitset(~_present & all_bits); } + + /// for_each, for_each_n + template + requires std::invocable + [[maybe_unused]] constexpr auto for_each(Fn&& func, Args&&... args) noexcept + { + return for_each_n(static_cast(countof), std::forward(func), std::forward(args)...); + } + + template // specialisation for member function with object + requires std::invocable + [[maybe_unused]] constexpr auto for_each(Fn&& func, C *obj, Args&&... args) noexcept + { + return for_each(std::bind(std::forward(func), obj, std::placeholders::_1, std::forward(args)...)); + } + + template + requires std::invocable + [[maybe_unused]] constexpr auto for_each_n(int n, Fn&& func, Args&&... args) noexcept + { + for (int ii{}, jj{}; ii < static_cast(countof) && jj < n; ++ii) + if (const auto ev{conjure_enum::values[ii]}; test(ev)) + std::invoke(std::forward(func), ev, std::forward(args)...), ++jj; + return std::bind(std::forward(func), std::placeholders::_1, std::forward(args)...); + } + + template // specialisation for member function with object + requires std::invocable + [[maybe_unused]] constexpr auto for_each_n(int n, Fn&& func, C *obj, Args&&... args) noexcept + { + return for_each_n(n, std::bind(std::forward(func), obj, std::placeholders::_1, std::forward(args)...)); + } + + /// create a bitset from custom separated enum string + static constexpr U factory(std::string_view src, bool anyscope, char sep, bool ignore_errors) + { + enum_bitset result; + constexpr auto trim([](std::string_view src) noexcept ->auto + { + const auto bg(src.find_first_not_of(" \t")); + return bg == std::string_view::npos ? src : src.substr(bg, src.find_last_not_of(" \t") - bg + 1); + }); + auto process([anyscope,&result](std::string_view src) noexcept ->auto + { + if (anyscope && !conjure_enum::has_scope(src)) + src = conjure_enum::add_scope(src); + if (auto ev { conjure_enum::string_to_enum(src) }; ev) + { + result |= *ev; + return true; + } + return false; + }); + for (std::string_view::size_type pos{}, fnd{};; pos = fnd + 1) + { + if ((fnd = src.find_first_of(sep, pos)) != std::string_view::npos) + { + if (auto srcp { trim(src.substr(pos, fnd - pos)) }; !process(trim(srcp)) && !ignore_errors) + throw std::invalid_argument(std::string(srcp).c_str()); + continue; + } + if (pos < src.size()) + if (auto srcp { trim(src.substr(pos, src.size() - pos)) }; !process(trim(srcp)) && !ignore_errors) + throw std::invalid_argument(std::string(srcp).c_str()); + break; + } + return result._present; + } + + constexpr std::string to_string(char zero='0', char one='1') const noexcept + { + return std::bitset(_present).to_string(zero, one); + } + + friend constexpr std::ostream& operator<<(std::ostream& os, const enum_bitset& what) noexcept + { + return os << what.to_string(); + } +}; + +template +constexpr enum_bitset operator&(const enum_bitset& lh, const enum_bitset& rh) noexcept + { return lh.operator&(rh.to_ulong()); } +template +constexpr enum_bitset operator|(const enum_bitset& lh, const enum_bitset& rh) noexcept + { return lh.operator|(rh.to_ulong()); } +template +constexpr enum_bitset operator^(const enum_bitset& lh, const enum_bitset& rh) noexcept + { return lh.operator^(rh.to_ulong()); } + +//----------------------------------------------------------------------------------------- +} // FIX8 + +#endif // FIX8_CONJURE_ENUM_BITSET_HPP_ + diff --git a/include/fix8/conjure_enum_ext.hpp b/include/fix8/conjure_enum_ext.hpp new file mode 100644 index 0000000..6cfad2e --- /dev/null +++ b/include/fix8/conjure_enum_ext.hpp @@ -0,0 +1,239 @@ +//----------------------------------------------------------------------------------------- +// SPDX-License-Identifier: MIT +// SPDX-FileCopyrightText: Copyright (C) 2024 Fix8 Market Technologies Pty Ltd +// SPDX-FileType: SOURCE +// +// conjure_enum (header only) +// by David L. Dight +// see https://github.com/fix8mt/conjure_enum +// +// Lightweight header-only C++20 enum and typename reflection +// +// Parts based on magic_enum +// Copyright (c) 2019 - 2024 Daniil Goncharov . +// +// Licensed under the MIT License . +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is furnished +// to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice (including the next paragraph) +// shall be included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +//---------------------------------------------------------------------------------------- +// Full build include fragment +//---------------------------------------------------------------------------------------- +#ifndef FIX8_CONJURE_ENUM_EXT_HPP_ +#define FIX8_CONJURE_ENUM_EXT_HPP_ + +//---------------------------------------------------------------------------------------- +private: + template + static constexpr auto _names(std::index_sequence) noexcept + { + return std::array{{{ _enum_name_v}...}}; + } + + template + static constexpr auto _unscoped_entries(std::index_sequence) noexcept + { + std::array tmp{{{ values[I], _remove_scope(_enum_name_v)}...}}; + std::sort(tmp.begin(), tmp.end(), _tuple_comp_rev); + return tmp; + } + + static constexpr std::string_view _remove_scope(std::string_view what) noexcept + { + if (const auto lc { what.find_last_of(':') }; lc != std::string_view::npos) + return what.substr(lc + 1); + return what; + } + + template + static constexpr auto _scoped_entries(std::index_sequence) noexcept + { + std::array tmp{{{ _remove_scope(_enum_name_v), _enum_name_v}...}}; + std::sort(tmp.begin(), tmp.end(), _scoped_comp); + return tmp; + } + + template + static constexpr auto _rev_scoped_entries(std::index_sequence) noexcept + { + std::array tmp{{{ _enum_name_v, _remove_scope(_enum_name_v)}...}}; + std::sort(tmp.begin(), tmp.end(), _scoped_comp); + return tmp; + } + + template + static constexpr auto _unscoped_names(std::index_sequence) noexcept + { + return std::array{{{ _remove_scope(_enum_name_v)}...}}; + } + + static constexpr std::string_view _process_scope([[maybe_unused]] const auto& entr, std::string_view what) noexcept + { + if constexpr (is_scoped()) + if (const auto result { std::equal_range(entr.cbegin(), + entr.cend(), scoped_tuple(what, std::string_view()), _scoped_comp) }; + result.first != result.second) + return std::get<1>(*result.first); + return what; + } + + static constexpr bool _scoped_comp(const scoped_tuple& pl, const scoped_tuple& pr) noexcept + { + return std::get<0>(pl) < std::get<0>(pr); + } + +public: + static constexpr std::string_view remove_scope(std::string_view what) noexcept + { + return _process_scope(rev_scoped_entries, what); + } + + static constexpr std::string_view add_scope(std::string_view what) noexcept + { + return _process_scope(scoped_entries, what); + } + + // iterators + static constexpr auto cbegin() noexcept { return entries.cbegin(); } + static constexpr auto cend() noexcept { return entries.cend(); } + static constexpr auto crbegin() noexcept { return entries.crbegin(); } + static constexpr auto crend() noexcept { return entries.crend(); } + static constexpr auto front() noexcept { return *cbegin(); } + static constexpr auto back() noexcept { return *std::prev(cend()); } + static constexpr std::optional unscoped_string_to_enum(std::string_view str) noexcept + { + if (const auto result { std::equal_range(unscoped_entries.cbegin(), unscoped_entries.cend(), enum_tuple(T{}, str), _tuple_comp_rev) }; + result.first != result.second) + return std::get(*result.first); + return {}; + } + + /// for_each, for_each_n + template + requires std::invocable + [[maybe_unused]] static constexpr auto for_each(Fn&& func, Args&&... args) noexcept + { + return for_each_n(static_cast(count()), std::forward(func), std::forward(args)...); + } + + template // specialisation for member function with object + requires std::invocable + [[maybe_unused]] static constexpr auto for_each(Fn&& func, C *obj, Args&&... args) noexcept + { + return for_each(std::bind(std::forward(func), obj, std::placeholders::_1, std::forward(args)...)); + } + + template + requires std::invocable + [[maybe_unused]] static constexpr auto for_each_n(int n, Fn&& func, Args&&... args) noexcept + { + for (int ii{}; const auto ev : conjure_enum::values) + { + if (ii++ >= n) + break; + std::invoke(std::forward(func), ev, std::forward(args)...); + } + return std::bind(std::forward(func), std::placeholders::_1, std::forward(args)...); + } + + template // specialisation for member function with object + requires std::invocable + [[maybe_unused]] static constexpr auto for_each_n(int n, Fn&& func, C *obj, Args&&... args) noexcept + { + return for_each_n(n, std::bind(std::forward(func), obj, std::placeholders::_1, std::forward(args)...)); + } + + // dispatch + template + static constexpr bool tuple_comp(const std::tuple& pl, const std::tuple& pr) noexcept + { + return static_cast(std::get(pl)) < static_cast(std::get(pr)); + } + + template // with not found value(nval) for return + requires std::invocable + [[maybe_unused]] static constexpr R dispatch(T ev, R nval, const std::array, I>& disp, Args&&... args) noexcept + { + const auto result { std::equal_range(disp.cbegin(), disp.cend(), std::make_tuple(ev, Fn()), tuple_comp) }; + return result.first != result.second ? std::invoke(std::get(*result.first), ev, std::forward(args)...) : nval; + } + + template // specialisation for member function with not found value(nval) for return + requires std::invocable + [[maybe_unused]] static constexpr R dispatch(T ev, R nval, const std::array, I>& disp, C *obj, Args&&... args) noexcept + { + const auto result { std::equal_range(disp.cbegin(), disp.cend(), std::make_tuple(ev, Fn()), tuple_comp) }; + return result.first != result.second ? std::invoke(std::get(*result.first), obj, ev, std::forward(args)...) : nval; + } + + template // void func with not found call to last element + requires (std::invocable && I > 0) + static constexpr void dispatch(T ev, const std::array, I>& disp, Args&&... args) noexcept + { + const auto result { std::equal_range(disp.cbegin(), std::prev(disp.cend()), std::make_tuple(ev, Fn()), tuple_comp) }; + return result.first != result.second ? std::invoke(std::get(*result.first), ev, std::forward(args)...) + : std::invoke(std::get(*std::prev(disp.cend())), ev, std::forward(args)...); + } + + template // specialisation for void member function with not found call to last element + requires (std::invocable && I > 0) + static constexpr void dispatch(T ev, const std::array, I>& disp, C *obj, Args&&... args) noexcept + { + const auto result { std::equal_range(disp.cbegin(), std::prev(disp.cend()), std::make_tuple(ev, Fn()), tuple_comp) }; + return result.first != result.second ? std::invoke(std::get(*result.first), obj, ev, std::forward(args)...) + : std::invoke(std::get(*std::prev(disp.cend())), obj, ev, std::forward(args)...); + } + + // public constexpr data structures + static constexpr auto names { _names(std::make_index_sequence()) }; + static constexpr auto scoped_entries { _scoped_entries(std::make_index_sequence()) }; + static constexpr auto unscoped_entries { _unscoped_entries(std::make_index_sequence()) }; + static constexpr auto rev_scoped_entries { _rev_scoped_entries(std::make_index_sequence()) }; + static constexpr auto unscoped_names { _unscoped_names(std::make_index_sequence()) }; +}; + +//----------------------------------------------------------------------------------------- +// allow range based for +template +struct iterator_adaptor +{ + constexpr auto begin() noexcept { return conjure_enum::entries.cbegin(); } + constexpr auto end() noexcept { return conjure_enum::entries.cend(); } +}; + +//----------------------------------------------------------------------------------------- +#include + +//----------------------------------------------------------------------------------------- +// ostream& operator<< for any enum; add the following before using: +// using ostream_enum_operator::operator<<; +//----------------------------------------------------------------------------------------- +namespace ostream_enum_operator +{ + template, valid_enum T> + constexpr std::basic_ostream& operator<<(std::basic_ostream& os, T value) noexcept + { + if (conjure_enum::contains(value)) + return os << conjure_enum::enum_to_string(value); + return os << conjure_enum::enum_to_underlying(value); + } +} + +//----------------------------------------------------------------------------------------- + +#endif // FIX8_CONJURE_ENUM_EXT_HPP_ + diff --git a/include/fix8/conjure_type.hpp b/include/fix8/conjure_type.hpp new file mode 100644 index 0000000..e12b06a --- /dev/null +++ b/include/fix8/conjure_type.hpp @@ -0,0 +1,112 @@ +//----------------------------------------------------------------------------------------- +// SPDX-License-Identifier: MIT +// SPDX-FileCopyrightText: Copyright (C) 2024 Fix8 Market Technologies Pty Ltd +// SPDX-FileType: SOURCE +// +// conjure_enum (header only) +// by David L. Dight +// see https://github.com/fix8mt/conjure_enum +// +// Lightweight header-only C++20 enum and typename reflection +// +// Parts based on magic_enum +// Copyright (c) 2019 - 2024 Daniil Goncharov . +// +// Licensed under the MIT License . +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is furnished +// to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice (including the next paragraph) +// shall be included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +//---------------------------------------------------------------------------------------- +// conjure_type +//---------------------------------------------------------------------------------------- +#ifndef FIX8_CONJURE_TYPE_HPP_ +#define FIX8_CONJURE_TYPE_HPP_ + +//----------------------------------------------------------------------------------------- +namespace FIX8 { + +//----------------------------------------------------------------------------------------- +// General purpose class allowing you to extract a string representation of any typename. +// The string will be stored statically by the compiler, so you can use the statically generated value `name` to obtain your type. +//----------------------------------------------------------------------------------------- +template +class conjure_type : public static_only +{ + static constexpr std::string_view _get_name() noexcept + { + constexpr std::string_view from{tpeek()}; +#if defined _MSC_VER + constexpr auto ep { from.rfind(cs::get_spec()) }; + if constexpr (ep == std::string_view::npos) + return {}; + if constexpr (constexpr auto lc { from.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) + { + constexpr auto e1 { from.substr(lc + 1, ep - lc - 2) }; + CHKMSSTR(e1,type_t); + CHKMSSTR(e1,extype_t0); + CHKMSSTR(e1,extype_t1); + CHKMSSTR(e1,extype_t2); + CHKMSSTR(e1,extype_t3); + } + return {}; + } +#else + constexpr auto ep { from.rfind(cs::get_spec()) }; + if constexpr (ep == std::string_view::npos) + return {}; + if constexpr (from[ep + cs::get_spec().size()] == cs::get_spec()) + if (constexpr auto lstr { from.substr(ep + cs::get_spec().size()) }; + lstr.find(cs::get_spec()) != std::string_view::npos) // is anon + if constexpr (constexpr auto lc { lstr.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) + return lstr.substr(cs::get_spec().size() + 2, lc - (cs::get_spec().size() + 2)); // eat "::" + constexpr auto result { from.substr(ep + cs::get_spec().size()) }; + if constexpr (constexpr auto lc { result.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) + return result.substr(0, lc); + return {}; + } + static constexpr auto _type_name() noexcept + { + constexpr auto result { _get_name() }; + return fixed_string(result); + } +#endif + +public: + static consteval const char *tpeek() noexcept { return std::source_location::current().function_name(); } + static constexpr auto name + { +#if defined _MSC_VER + _get_name() +#else + _type_name() +#endif + }; + static constexpr std::string_view as_string_view() noexcept + { +#if defined _MSC_VER + return name; +#else + return name.get(); +#endif + } +}; + +//----------------------------------------------------------------------------------------- +} // FIX8 + +#endif // FIX8_CONJURE_TYPE_HPP_ + diff --git a/utests/edgetests.cpp b/utests/edgetests.cpp index 9a95cfa..391562c 100644 --- a/utests/edgetests.cpp +++ b/utests/edgetests.cpp @@ -31,6 +31,7 @@ #include #include #include +#include //----------------------------------------------------------------------------------------- class foobat{}; diff --git a/utests/unittests.cpp b/utests/unittests.cpp index cc8ece4..71c7d66 100644 --- a/utests/unittests.cpp +++ b/utests/unittests.cpp @@ -34,6 +34,8 @@ #include #include #include +#include +#include //----------------------------------------------------------------------------------------- using namespace FIX8; From 88de780fa35215b3d1a63eafc9e6b10369e9b67b Mon Sep 17 00:00:00 2001 From: David Dight Date: Tue, 6 Aug 2024 07:59:58 +1000 Subject: [PATCH 024/235] updated --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3ed2fa1..2de524a 100644 --- a/README.md +++ b/README.md @@ -1168,7 +1168,7 @@ The string will be stored statically by the compiler, so you can use the statica > #include > ``` -## `name` +## a) `name` This static member is generated for your type. It is a `fixed_string` but has a built-in `std::string_view` operator. ```c++ template @@ -1228,6 +1228,12 @@ _output_ std::basic_string_view ``` +## b) `as_string_view` +Return the name as a `std::string_view`. +```c++ +static constexpr std::string_view as_string_view(); +``` + --- # 6. Building This implementation is header only. Apart from standard C++20 includes there are no external dependencies needed in your application. From d14c09de62c484d38155764ffcbd54b4d79eac78 Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 7 Aug 2024 05:38:41 +1000 Subject: [PATCH 025/235] updated --- README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/README.md b/README.md index 2de524a..0ae8901 100644 --- a/README.md +++ b/README.md @@ -1234,6 +1234,23 @@ Return the name as a `std::string_view`. static constexpr std::string_view as_string_view(); ``` +## c) `tpeek` +```c++ +static consteval const char *tpeek(); +``` + +These functions return `std::source_location::current().function_name()` as `const char*` strings for type. +The actual output is implementation dependent. See [Results of `source_location`](reference/source_location.md) for implementation specific `std::source_location` results. + +The following code: +```c++ +std::cout << conjure_type::tpeek() << '\n'; +``` +Generates this output with gcc: +```CSV +static consteval const char* FIX8::conjure_type::tpeek() [with T = test] +``` + --- # 6. Building This implementation is header only. Apart from standard C++20 includes there are no external dependencies needed in your application. From fe3ae1b369a9b4fb8af87422cff25684d076b24c Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 8 Aug 2024 06:18:32 +1000 Subject: [PATCH 026/235] updated --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0ae8901..153f6b0 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,8 @@ > [!TIP] > Use the built-in [table of contents](https://github.blog/changelog/2021-04-13-table-of-contents-support-in-markdown-files/) to navigate this guide. > Even better in [full read view](./README.md) of this page. +> +> For the latest cutting edge changes, see the [dev branch](https://github.com/fix8mt/conjure_enum/tree/dev). --- # 2. Introduction @@ -66,14 +68,12 @@ Based on the awesome work in [`magic_enum`](https://github.com/Neargye/magic_enu this library offers a streamlined and powerful way to add reflection capabilities to your C++ enums and other types. We've optimized the core functionality, focusing on the main features developers usually want. We've also added general purpose typename reflection for any type. -For the latest cutting edge changes, see the [dev branch](https://github.com/fix8mt/conjure_enum/tree/dev). - ## b) Embracing C++20 `conjure_enum`[^1] takes full advantage of recently added C++20 features. We've leveraged the convenience of [`std::source_location`](https://en.cppreference.com/w/cpp/utility/source_location) and unlocked the potential of [`constexpr` algorithms](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0202r3.html) and [concepts](https://en.cppreference.com/w/cpp/language/constraints). -## c) Key Benefits +## c) Highlights - ***Single Header-Only***: No external dependencies, simplifying integration into your project - ***Modern C++20***: Entirely `constexpr` for compile-time safety, efficiency and performance; no macros From b8e95cc6b89a4ed1f01f2b338b6a0ce975d2a1ef Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 8 Aug 2024 06:20:20 +1000 Subject: [PATCH 027/235] updated --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 153f6b0..24323a2 100644 --- a/README.md +++ b/README.md @@ -46,8 +46,8 @@ --|--|-- |1|[Implementation](include/fix8/conjure_enum.hpp)| For header implementation| |2|[`conjure_enum` API and Examples](#3-api-and-examples-using-conjure_enum)| General examples| -|3|[`enum_bitset` API and Examples](#4-api-and-examples-using-enum_bitset)| enhanced enum aware `std::bitset`| -|4|[`conjure_type` API and Examples](#5-api-and-examples-using-conjure_type)| any type string extractor| +|3|[`enum_bitset` API and Examples](#4-api-and-examples-using-enum_bitset)| Enhanced enum aware `std::bitset`| +|4|[`conjure_type` API and Examples](#5-api-and-examples-using-conjure_type)| Any type string extractor| |5|[Building](#6-building)| How to build or include| |6|[vcpkg](https://vcpkg.io/en/package/conjure-enum)| For vcpkg package| |7|[Notes](#7-notes)| Notes on the implementation, limits, etc| From c4c6facd7e00bf95d29e55d887ccac4c8260da08 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sun, 11 Aug 2024 06:35:48 +1000 Subject: [PATCH 028/235] updated --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 24323a2..f661d74 100644 --- a/README.md +++ b/README.md @@ -676,7 +676,7 @@ _output_ true false ``` -## s) `type_name` +## s) `type_name` ![](assets/notminimalred.svg) ```c++ static constexpr std::string_view type_name(); ``` @@ -1467,6 +1467,7 @@ remove_scope add_scope unscoped_string_to_enum for_each,for_each_n +type_name dispatch iterators enum_to_string //noscope option not available @@ -1602,7 +1603,7 @@ $ It can be observed that there is only _one_ copy of the scoped enum value string in the executable. -## f) Clang compile profiling +## f) Compilation profiling (Clang) You can profile the compile time for Clang (other compilers TBA). Firstly install [ClangBuildAnalyzer](https://github.com/aras-p/ClangBuildAnalyzer). Then configure `conjure_enum` with: ```CMake From bd4ffbf7c250c577541dd32de56f8d16ce942f04 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sun, 11 Aug 2024 06:35:59 +1000 Subject: [PATCH 029/235] pre-rel 1.0.2c --- CMakeLists.txt | 10 +++++----- examples/cbenchmark.cpp | 4 ++++ include/fix8/conjure_enum.hpp | 31 ++++--------------------------- include/fix8/conjure_enum_ext.hpp | 27 +++++++++++++++++++++++++++ 4 files changed, 40 insertions(+), 32 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e6a06e0..fa679ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,28 +33,28 @@ project (conjure_enum LANGUAGES CXX HOMEPAGE_URL https://github.com/fix8mt/conjure_enum DESCRIPTION "Lightweight C++20 enum and typename reflection" - VERSION 1.0.0) + VERSION 1.0.2) # to disable strip: # cmake -DBUILD_STRIP_EXE=false .. option(BUILD_STRIP_EXE "enable stripping of non-unittest executables" true) -message("-- Build strip exes: ${BUILD_STRIP_EXE}") +message("-- Build: strip exes ${BUILD_STRIP_EXE}") # to disable warnings: # cmake -DBUILD_ALL_WARNINGS=false .. option(BUILD_ALL_WARNINGS "enable building with all warnings" true) -message("-- Build with all warnings : ${BUILD_ALL_WARNINGS}") +message("-- Build: with all warnings ${BUILD_ALL_WARNINGS}") # to disable building unit tests: # cmake -DBUILD_UNITTESTS=false .. option(BUILD_UNITTESTS "enable building unit tests" true) -message("-- Build unit tests: ${BUILD_UNITTESTS}") +message("-- Build: unit tests ${BUILD_UNITTESTS}") # to enable clang build profiler: # cmake -DBUILD_CLANG_PROFILER=true .. # see examples/cbenchmark.sh option(BUILD_CLANG_PROFILER "enable clang build profiler" false) -message("-- Build clang profiler: ${BUILD_CLANG_PROFILER}") +message("-- Build: clang profiler ${BUILD_CLANG_PROFILER}") if(BUILD_CLANG_PROFILER) if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") add_compile_options(-ftime-trace) diff --git a/examples/cbenchmark.cpp b/examples/cbenchmark.cpp index 31620db..98259a7 100644 --- a/examples/cbenchmark.cpp +++ b/examples/cbenchmark.cpp @@ -28,6 +28,10 @@ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. //---------------------------------------------------------------------------------------- +// CLI msvc build benchmark from your build dir +// call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat" +// cl /nologo /MD /std:c++latest /Bt+ /I ..\include ..\examples\cbenchmark.cpp|find "c1xx.dll" +//---------------------------------------------------------------------------------------- #include #define FIX8_CONJURE_ENUM_MINIMAL #include diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index f769f1f..fa39317 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -212,6 +212,7 @@ class conjure_enum : public static_only if constexpr (constexpr auto ep { from.rfind(cs::get_spec()) }; ep == std::string_view::npos) return false; #if defined __clang__ +#if not defined FIX8_CONJURE_ENUM_MINIMAL else if constexpr (from[ep + cs::get_spec().size()] == '(') { if constexpr (from[ep + cs::get_spec().size() + 1] == '(') @@ -220,6 +221,7 @@ class conjure_enum : public static_only lstr.find(cs::get_spec()) != std::string_view::npos) // is anon return true; } +#endif else if constexpr (from.substr(ep + cs::get_spec().size()).find_first_of(cs::get_spec()) != std::string_view::npos) return true; return false; @@ -252,6 +254,7 @@ class conjure_enum : public static_only constexpr auto ep { from.rfind(cs::get_spec()) }; if constexpr (ep == std::string_view::npos) return {}; +#if not defined FIX8_CONJURE_ENUM_MINIMAL if constexpr (from[ep + cs::get_spec().size()] == cs::get_spec()) { #if defined __clang__ @@ -263,6 +266,7 @@ class conjure_enum : public static_only if constexpr (constexpr auto lc { lstr.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) return lstr.substr(cs::get_spec().size() + 2, lc - (cs::get_spec().size() + 2)); // eat "::" } +#endif constexpr std::string_view result { from.substr(ep + cs::get_spec().size()) }; if constexpr (constexpr auto lc { result.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) return result.substr(0, lc); @@ -290,33 +294,6 @@ class conjure_enum : public static_only template static consteval const char *epeek() noexcept { return std::source_location::current().function_name(); } - static constexpr std::string_view type_name() noexcept - { - constexpr std::string_view from{tpeek()}; -#if defined _MSC_VER - constexpr auto ep { from.rfind(cs::get_spec()) }; - if constexpr (ep == std::string_view::npos) - return {}; - if constexpr (constexpr auto lc { from.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) - { - constexpr auto e1 { from.substr(lc + 1, ep - lc - 2) }; - CHKMSSTR(e1,type_t); - CHKMSSTR(e1,extype_t1); - } - else - return {}; -#else - if constexpr (constexpr auto ep { from.rfind(cs::get_spec()) }; ep != std::string_view::npos) - { - constexpr auto result { from.substr(ep + cs::get_spec().size()) }; - if constexpr (constexpr auto lc { result.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) - return result.substr(0, lc); - } - else - return {}; -#endif - } - struct is_scoped : std::bool_constant>; diff --git a/include/fix8/conjure_enum_ext.hpp b/include/fix8/conjure_enum_ext.hpp index 6cfad2e..2897490 100644 --- a/include/fix8/conjure_enum_ext.hpp +++ b/include/fix8/conjure_enum_ext.hpp @@ -122,6 +122,33 @@ return {}; } + static constexpr std::string_view type_name() noexcept + { + constexpr std::string_view from{tpeek()}; +#if defined _MSC_VER + constexpr auto ep { from.rfind(cs::get_spec()) }; + if constexpr (ep == std::string_view::npos) + return {}; + if constexpr (constexpr auto lc { from.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) + { + constexpr auto e1 { from.substr(lc + 1, ep - lc - 2) }; + CHKMSSTR(e1,type_t); + CHKMSSTR(e1,extype_t1); + } + else + return {}; +#else + if constexpr (constexpr auto ep { from.rfind(cs::get_spec()) }; ep != std::string_view::npos) + { + constexpr auto result { from.substr(ep + cs::get_spec().size()) }; + if constexpr (constexpr auto lc { result.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) + return result.substr(0, lc); + } + else + return {}; +#endif + } + /// for_each, for_each_n template requires std::invocable From 35be85d16b00978351df1eea36bf407fcc536aee Mon Sep 17 00:00:00 2001 From: David Dight Date: Sun, 11 Aug 2024 07:18:56 +1000 Subject: [PATCH 030/235] pre-rel 1.0.2c --- include/fix8/conjure_enum.hpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index fa39317..e5d3b05 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -212,22 +212,22 @@ class conjure_enum : public static_only if constexpr (constexpr auto ep { from.rfind(cs::get_spec()) }; ep == std::string_view::npos) return false; #if defined __clang__ -#if not defined FIX8_CONJURE_ENUM_MINIMAL else if constexpr (from[ep + cs::get_spec().size()] == '(') { if constexpr (from[ep + cs::get_spec().size() + 1] == '(') return false; +#if not defined FIX8_CONJURE_ENUM_MINIMAL if constexpr (constexpr auto lstr { from.substr(ep + cs::get_spec().size()) }; lstr.find(cs::get_spec()) != std::string_view::npos) // is anon +#endif return true; } -#endif else if constexpr (from.substr(ep + cs::get_spec().size()).find_first_of(cs::get_spec()) != std::string_view::npos) return true; return false; #else else if constexpr (from[ep + cs::get_spec().size()] != '(' - && from.substr(ep + cs::get_spec().size()).find_first_of(cs::get_spec()) != std::string_view::npos) + && from.find_first_of(cs::get_spec(), ep + cs::get_spec().size()) != std::string_view::npos) return true; else return false; @@ -344,13 +344,11 @@ class conjure_enum : public static_only // contains static constexpr bool contains(T value) noexcept { - const auto result { std::equal_range(values.cbegin(), values.cend(), value, _value_comp) }; - return result.first != result.second; + return std::binary_search(values.cbegin(), values.cend(), value, _value_comp); } static constexpr bool contains(std::string_view str) noexcept { - const auto result { std::equal_range(sorted_entries.cbegin(), sorted_entries.cend(), enum_tuple(T{}, str), _tuple_comp_rev) }; - return result.first != result.second; + return std::binary_search(sorted_entries.cbegin(), sorted_entries.cend(), enum_tuple(T{}, str), _tuple_comp_rev); } template static constexpr bool contains() noexcept { return contains(e); } From a802f4601c0e4ca8eb4491690b117cea3db82f92 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sun, 11 Aug 2024 08:03:24 +1000 Subject: [PATCH 031/235] pre-rel 1.0.2c --- include/fix8/conjure_enum.hpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index e5d3b05..7b93d8d 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -208,7 +208,7 @@ class conjure_enum : public static_only template static constexpr bool _is_valid() noexcept { - constexpr std::string_view from{epeek()}; + constexpr std::string_view from{_epeek_v}; if constexpr (constexpr auto ep { from.rfind(cs::get_spec()) }; ep == std::string_view::npos) return false; #if defined __clang__ @@ -216,13 +216,10 @@ class conjure_enum : public static_only { if constexpr (from[ep + cs::get_spec().size() + 1] == '(') return false; -#if not defined FIX8_CONJURE_ENUM_MINIMAL - if constexpr (constexpr auto lstr { from.substr(ep + cs::get_spec().size()) }; - lstr.find(cs::get_spec()) != std::string_view::npos) // is anon -#endif - return true; + if constexpr (from.find(cs::get_spec(), ep + cs::get_spec().size()) != std::string_view::npos) // is anon + return true; } - else if constexpr (from.substr(ep + cs::get_spec().size()).find_first_of(cs::get_spec()) != std::string_view::npos) + else if constexpr (from.find_first_of(cs::get_spec(), ep + cs::get_spec().size()) != std::string_view::npos) return true; return false; #else @@ -250,11 +247,10 @@ class conjure_enum : public static_only template static constexpr std::string_view _get_name() noexcept { - constexpr std::string_view from{epeek()}; + constexpr std::string_view from{_epeek_v}; constexpr auto ep { from.rfind(cs::get_spec()) }; if constexpr (ep == std::string_view::npos) return {}; -#if not defined FIX8_CONJURE_ENUM_MINIMAL if constexpr (from[ep + cs::get_spec().size()] == cs::get_spec()) { #if defined __clang__ @@ -266,7 +262,6 @@ class conjure_enum : public static_only if constexpr (constexpr auto lc { lstr.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) return lstr.substr(cs::get_spec().size() + 2, lc - (cs::get_spec().size() + 2)); // eat "::" } -#endif constexpr std::string_view result { from.substr(ep + cs::get_spec().size()) }; if constexpr (constexpr auto lc { result.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) return result.substr(0, lc); @@ -294,6 +289,11 @@ class conjure_enum : public static_only template static consteval const char *epeek() noexcept { return std::source_location::current().function_name(); } +private: + template + static constexpr std::string_view _epeek_v { epeek() }; + +public: struct is_scoped : std::bool_constant>; From 810b61bc5898fdebf1b5d8e79c54f26864aab890 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sun, 11 Aug 2024 08:08:18 +1000 Subject: [PATCH 032/235] pre-rel 1.0.2c --- include/fix8/conjure_enum.hpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 7b93d8d..fbbf5f3 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -181,6 +181,11 @@ class conjure_enum : public static_only using enum_tuple = std::tuple; using scoped_tuple = std::tuple; + static constexpr const char *tpeek() noexcept { return std::source_location::current().function_name(); } + + template + static constexpr const char *epeek() noexcept { return std::source_location::current().function_name(); } + private: template static constexpr auto _enum_name() noexcept @@ -205,6 +210,9 @@ class conjure_enum : public static_only return tmp; } + template + static constexpr std::string_view _epeek_v { epeek() }; + template static constexpr bool _is_valid() noexcept { @@ -283,16 +291,6 @@ class conjure_enum : public static_only return std::get(pl) < std::get(pr); } -public: - static consteval const char *tpeek() noexcept { return std::source_location::current().function_name(); } - - template - static consteval const char *epeek() noexcept { return std::source_location::current().function_name(); } - -private: - template - static constexpr std::string_view _epeek_v { epeek() }; - public: struct is_scoped : std::bool_constant Date: Sun, 11 Aug 2024 08:08:57 +1000 Subject: [PATCH 033/235] pre-rel 1.0.2c --- include/fix8/conjure_enum.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index fbbf5f3..03c1206 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -181,10 +181,10 @@ class conjure_enum : public static_only using enum_tuple = std::tuple; using scoped_tuple = std::tuple; - static constexpr const char *tpeek() noexcept { return std::source_location::current().function_name(); } + static consteval const char *tpeek() noexcept { return std::source_location::current().function_name(); } template - static constexpr const char *epeek() noexcept { return std::source_location::current().function_name(); } + static consteval const char *epeek() noexcept { return std::source_location::current().function_name(); } private: template From 76b15287e84bfbd93c23434f7ab630fc43b225be Mon Sep 17 00:00:00 2001 From: David Dight Date: Sun, 11 Aug 2024 08:11:20 +1000 Subject: [PATCH 034/235] pre-rel 1.0.2c --- include/fix8/conjure_enum.hpp | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 03c1206..a568c98 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -216,23 +216,22 @@ class conjure_enum : public static_only template static constexpr bool _is_valid() noexcept { - constexpr std::string_view from{_epeek_v}; - if constexpr (constexpr auto ep { from.rfind(cs::get_spec()) }; ep == std::string_view::npos) + if constexpr (constexpr auto ep { _epeek_v.rfind(cs::get_spec()) }; ep == std::string_view::npos) return false; #if defined __clang__ - else if constexpr (from[ep + cs::get_spec().size()] == '(') + else if constexpr (_epeek_v[ep + cs::get_spec().size()] == '(') { - if constexpr (from[ep + cs::get_spec().size() + 1] == '(') + if constexpr (_epeek_v[ep + cs::get_spec().size() + 1] == '(') return false; - if constexpr (from.find(cs::get_spec(), ep + cs::get_spec().size()) != std::string_view::npos) // is anon + if constexpr (_epeek_v.find(cs::get_spec(), ep + cs::get_spec().size()) != std::string_view::npos) // is anon return true; } - else if constexpr (from.find_first_of(cs::get_spec(), ep + cs::get_spec().size()) != std::string_view::npos) + else if constexpr (_epeek_v.find_first_of(cs::get_spec(), ep + cs::get_spec().size()) != std::string_view::npos) return true; return false; #else - else if constexpr (from[ep + cs::get_spec().size()] != '(' - && from.find_first_of(cs::get_spec(), ep + cs::get_spec().size()) != std::string_view::npos) + else if constexpr (_epeek_v[ep + cs::get_spec().size()] != '(' + && _epeek_v.find_first_of(cs::get_spec(), ep + cs::get_spec().size()) != std::string_view::npos) return true; else return false; @@ -255,22 +254,21 @@ class conjure_enum : public static_only template static constexpr std::string_view _get_name() noexcept { - constexpr std::string_view from{_epeek_v}; - constexpr auto ep { from.rfind(cs::get_spec()) }; + constexpr auto ep { _epeek_v.rfind(cs::get_spec()) }; if constexpr (ep == std::string_view::npos) return {}; - if constexpr (from[ep + cs::get_spec().size()] == cs::get_spec()) + if constexpr (_epeek_v[ep + cs::get_spec().size()] == cs::get_spec()) { #if defined __clang__ - if constexpr (from[ep + cs::get_spec().size() + 1] == cs::get_spec()) + if constexpr (_epeek_v[ep + cs::get_spec().size() + 1] == cs::get_spec()) return {}; #endif - if (constexpr auto lstr { from.substr(ep + cs::get_spec().size()) }; + if (constexpr auto lstr { _epeek_v.substr(ep + cs::get_spec().size()) }; lstr.find(cs::get_spec()) != std::string_view::npos) // is anon if constexpr (constexpr auto lc { lstr.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) return lstr.substr(cs::get_spec().size() + 2, lc - (cs::get_spec().size() + 2)); // eat "::" } - constexpr std::string_view result { from.substr(ep + cs::get_spec().size()) }; + constexpr std::string_view result { _epeek_v.substr(ep + cs::get_spec().size()) }; if constexpr (constexpr auto lc { result.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) return result.substr(0, lc); else From 45074190193c8ff26bcfdfa187e72209fc7e40d4 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sun, 11 Aug 2024 08:25:47 +1000 Subject: [PATCH 035/235] pre-rel 1.0.2c --- include/fix8/conjure_enum.hpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index a568c98..c84516c 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -105,6 +105,7 @@ class static_only //----------------------------------------------------------------------------------------- class cs : public static_only { + /* static constexpr auto _specifics { std::to_array> @@ -122,6 +123,28 @@ class cs : public static_only #endif }) }; + */ + +#if defined __clang__ + static constexpr std::array, 2> _specifics + { + {{ "e = ", ']', "(anonymous namespace)", '(' }, { "T = ", ']', "(anonymous namespace)", '(' }}, + }; +#elif defined __GNUC__ + static constexpr std::array, 2> _specifics + { + {{ "e = ", ';', "", '<' }, { "T = ", ']', "{anonymous}", '{' }}, + }; +#elif defined _MSC_VER + static constexpr std::array, 6> _specifics + { + {{ "epeek<", '>', "`anonymous-namespace'", '`' }, { "::tpeek", '<', "enum `anonymous namespace'::", '\0' }, + { "", '\0', "`anonymous namespace'::", '\0' }, { "", '\0', "enum ", '\0' }, { "", '\0', "class ", '\0' }, + { "", '\0', "struct ", '\0' }}, + }; +#else +# error "conjure_enum not supported by your compiler" +#endif public: enum class stype { enum_t, type_t, extype_t0, extype_t1, extype_t2, extype_t3 }; From 1a269487027d1a8646faa1030fcd77ee515a9916 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sun, 11 Aug 2024 08:28:54 +1000 Subject: [PATCH 036/235] pre-rel 1.0.2c --- include/fix8/conjure_enum.hpp | 34 ++++++---------------------------- 1 file changed, 6 insertions(+), 28 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index c84516c..85ec9a4 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -103,48 +103,26 @@ class static_only //----------------------------------------------------------------------------------------- // compiler specifics //----------------------------------------------------------------------------------------- + using namespace std::literals::string_view_literals; class cs : public static_only { - /* static constexpr auto _specifics { std::to_array> ({ #if defined __clang__ - { "e = ", ']', "(anonymous namespace)", '(' }, { "T = ", ']', "(anonymous namespace)", '(' }, + { "e = "sv, ']', "(anonymous namespace)"sv, '(' }, { "T = "sv, ']', "(anonymous namespace)"sv, '(' }, #elif defined __GNUC__ - { "e = ", ';', "", '<' }, { "T = ", ']', "{anonymous}", '{' }, + { "e = "sv, ';', ""sv, '<' }, { "T = "sv, ']', "{anonymous}"sv, '{' }, #elif defined _MSC_VER - { "epeek<", '>', "`anonymous-namespace'", '`' }, { "::tpeek", '<', "enum `anonymous namespace'::", '\0' }, - { "", '\0', "`anonymous namespace'::", '\0' }, { "", '\0', "enum ", '\0' }, { "", '\0', "class ", '\0' }, - { "", '\0', "struct ", '\0' }, + { "epeek<"sv, '>', "`anonymous-namespace'"sv, '`' }, { "::tpeek"sv, '<', "enum `anonymous namespace'::"sv, '\0' }, + { ""sv, '\0', "`anonymous namespace'::"sv, '\0' }, { ""sv, '\0', "enum "sv, '\0' }, { ""sv, '\0', "class "sv, '\0' }, + { ""sv, '\0', "struct "sv, '\0' }, #else # error "conjure_enum not supported by your compiler" #endif }) }; - */ - -#if defined __clang__ - static constexpr std::array, 2> _specifics - { - {{ "e = ", ']', "(anonymous namespace)", '(' }, { "T = ", ']', "(anonymous namespace)", '(' }}, - }; -#elif defined __GNUC__ - static constexpr std::array, 2> _specifics - { - {{ "e = ", ';', "", '<' }, { "T = ", ']', "{anonymous}", '{' }}, - }; -#elif defined _MSC_VER - static constexpr std::array, 6> _specifics - { - {{ "epeek<", '>', "`anonymous-namespace'", '`' }, { "::tpeek", '<', "enum `anonymous namespace'::", '\0' }, - { "", '\0', "`anonymous namespace'::", '\0' }, { "", '\0', "enum ", '\0' }, { "", '\0', "class ", '\0' }, - { "", '\0', "struct ", '\0' }}, - }; -#else -# error "conjure_enum not supported by your compiler" -#endif public: enum class stype { enum_t, type_t, extype_t0, extype_t1, extype_t2, extype_t3 }; From adc39725638e7570d780a7fa2f5c46d59b65650d Mon Sep 17 00:00:00 2001 From: David Dight Date: Sun, 11 Aug 2024 08:34:13 +1000 Subject: [PATCH 037/235] pre-rel 1.0.2c --- include/fix8/conjure_enum.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 85ec9a4..5100f26 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -56,6 +56,8 @@ //----------------------------------------------------------------------------------------- namespace FIX8 { +using namespace std::literals::string_view_literals; + //----------------------------------------------------------------------------------------- // global default enum range //----------------------------------------------------------------------------------------- @@ -103,7 +105,6 @@ class static_only //----------------------------------------------------------------------------------------- // compiler specifics //----------------------------------------------------------------------------------------- - using namespace std::literals::string_view_literals; class cs : public static_only { static constexpr auto _specifics @@ -172,7 +173,7 @@ struct enum_range : public static_only //----------------------------------------------------------------------------------------- template -class conjure_enum : public static_only +class conjure_enum final : public static_only { static constexpr int enum_min_value{enum_range::min}, enum_max_value{enum_range::max}; static_assert(enum_max_value > enum_min_value, From 72a1651fcaf8b957f585d1e8a8d7156da9607190 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sun, 11 Aug 2024 08:35:57 +1000 Subject: [PATCH 038/235] pre-rel 1.0.2c --- include/fix8/conjure_enum.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 5100f26..9d0ffa8 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -105,7 +105,7 @@ class static_only //----------------------------------------------------------------------------------------- // compiler specifics //----------------------------------------------------------------------------------------- -class cs : public static_only +class cs final : public static_only { static constexpr auto _specifics { @@ -157,7 +157,7 @@ concept valid_enum = requires(T) // You can specialise this class to define a custom range for your enum //----------------------------------------------------------------------------------------- template -struct enum_range : public static_only +struct enum_range final : public static_only { static constexpr int min{FIX8_CONJURE_ENUM_MIN_VALUE}, max{FIX8_CONJURE_ENUM_MAX_VALUE}; }; From c53d36d34a9a64a25a8a1348001058113c2437ab Mon Sep 17 00:00:00 2001 From: David Dight Date: Sun, 11 Aug 2024 10:06:26 +1000 Subject: [PATCH 039/235] pre-rel 1.0.2c --- examples/cbenchmark.cpp | 1 + include/fix8/conjure_enum.hpp | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/examples/cbenchmark.cpp b/examples/cbenchmark.cpp index 98259a7..cab3889 100644 --- a/examples/cbenchmark.cpp +++ b/examples/cbenchmark.cpp @@ -34,6 +34,7 @@ //---------------------------------------------------------------------------------------- #include #define FIX8_CONJURE_ENUM_MINIMAL +#define FIX8_CONJURE_ENUM_BYPASS #include //----------------------------------------------------------------------------------------- diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 9d0ffa8..b5611d6 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -243,6 +243,7 @@ class conjure_enum final : public static_only template static constexpr auto _values(std::index_sequence) noexcept { +#if not defined FIX8_CONJURE_ENUM_BYPASS constexpr std::array valid { _is_valid(enum_min_value + I)>()... }; constexpr auto valid_cnt { std::count_if(valid.cbegin(), valid.cend(), [](bool val) noexcept { return val; }) }; static_assert(valid_cnt > 0, "conjure_enum requires non-empty enum"); @@ -250,6 +251,9 @@ class conjure_enum final : public static_only for(std::size_t idx{}, nn{}; nn < valid_cnt; ++idx) if (valid[idx]) vals[nn++] = static_cast(enum_min_value + idx); +#else + std::array vals{static_cast(enum_min_value + I)... }; +#endif return vals; } From 750653a7b1cdef1e7ebd9f3062d2f454213a066c Mon Sep 17 00:00:00 2001 From: David Dight Date: Sun, 11 Aug 2024 10:09:31 +1000 Subject: [PATCH 040/235] pre-rel 1.0.2d --- examples/cbenchmark.cpp | 2 +- include/fix8/conjure_enum.hpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/cbenchmark.cpp b/examples/cbenchmark.cpp index cab3889..e47604b 100644 --- a/examples/cbenchmark.cpp +++ b/examples/cbenchmark.cpp @@ -34,7 +34,7 @@ //---------------------------------------------------------------------------------------- #include #define FIX8_CONJURE_ENUM_MINIMAL -#define FIX8_CONJURE_ENUM_BYPASS +#define FIX8_CONJURE_ENUM_IS_CONTINUOUS #include //----------------------------------------------------------------------------------------- diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index b5611d6..9fa912b 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -243,7 +243,7 @@ class conjure_enum final : public static_only template static constexpr auto _values(std::index_sequence) noexcept { -#if not defined FIX8_CONJURE_ENUM_BYPASS +#if not defined FIX8_CONJURE_ENUM_IS_CONTINUOUS constexpr std::array valid { _is_valid(enum_min_value + I)>()... }; constexpr auto valid_cnt { std::count_if(valid.cbegin(), valid.cend(), [](bool val) noexcept { return val; }) }; static_assert(valid_cnt > 0, "conjure_enum requires non-empty enum"); @@ -252,6 +252,7 @@ class conjure_enum final : public static_only if (valid[idx]) vals[nn++] = static_cast(enum_min_value + idx); #else + static_assert(sizeof...(I) > 0, "conjure_enum requires non-empty enum"); std::array vals{static_cast(enum_min_value + I)... }; #endif return vals; From 1473be23b299c71178f5068c6e1cb969591c583d Mon Sep 17 00:00:00 2001 From: David Dight Date: Sun, 11 Aug 2024 10:11:47 +1000 Subject: [PATCH 041/235] pre-rel 1.0.2d --- include/fix8/conjure_enum.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 9fa912b..3082f84 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -251,11 +251,11 @@ class conjure_enum final : public static_only for(std::size_t idx{}, nn{}; nn < valid_cnt; ++idx) if (valid[idx]) vals[nn++] = static_cast(enum_min_value + idx); + return vals; #else static_assert(sizeof...(I) > 0, "conjure_enum requires non-empty enum"); - std::array vals{static_cast(enum_min_value + I)... }; + return std::array{static_cast(enum_min_value + I)... }; #endif - return vals; } template From 5a203b91c81efc18f419c243e5d58748d49cfdf5 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sun, 11 Aug 2024 10:22:31 +1000 Subject: [PATCH 042/235] pre-rel 1.0.2d --- include/fix8/conjure_enum.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 3082f84..df07d6e 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -243,7 +243,10 @@ class conjure_enum final : public static_only template static constexpr auto _values(std::index_sequence) noexcept { -#if not defined FIX8_CONJURE_ENUM_IS_CONTINUOUS +#if defined FIX8_CONJURE_ENUM_IS_CONTINUOUS + static_assert(sizeof...(I) > 0, "conjure_enum requires non-empty enum"); + return std::array{static_cast(enum_min_value + I)... }; +#else constexpr std::array valid { _is_valid(enum_min_value + I)>()... }; constexpr auto valid_cnt { std::count_if(valid.cbegin(), valid.cend(), [](bool val) noexcept { return val; }) }; static_assert(valid_cnt > 0, "conjure_enum requires non-empty enum"); @@ -252,9 +255,6 @@ class conjure_enum final : public static_only if (valid[idx]) vals[nn++] = static_cast(enum_min_value + idx); return vals; -#else - static_assert(sizeof...(I) > 0, "conjure_enum requires non-empty enum"); - return std::array{static_cast(enum_min_value + I)... }; #endif } From 77be465dae8f17598fe424fa665af3e50f6f30d0 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sun, 11 Aug 2024 10:24:59 +1000 Subject: [PATCH 043/235] pre-rel 1.0.2d --- include/fix8/conjure_enum.hpp | 3 --- include/fix8/conjure_enum_ext.hpp | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index df07d6e..6644f1d 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -302,9 +302,6 @@ class conjure_enum final : public static_only requires !std::convertible_to>; }>{}; - template - static constexpr bool is_valid() noexcept { return _is_valid(); } - static constexpr auto count() noexcept { return values.size(); } // scope ops diff --git a/include/fix8/conjure_enum_ext.hpp b/include/fix8/conjure_enum_ext.hpp index 2897490..3454e41 100644 --- a/include/fix8/conjure_enum_ext.hpp +++ b/include/fix8/conjure_enum_ext.hpp @@ -107,6 +107,9 @@ return _process_scope(scoped_entries, what); } + template + static constexpr bool is_valid() noexcept { return _is_valid(); } + // iterators static constexpr auto cbegin() noexcept { return entries.cbegin(); } static constexpr auto cend() noexcept { return entries.cend(); } From df7762d644a97055f91da73ec59e0fe4445eaf63 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sun, 11 Aug 2024 15:07:19 +1000 Subject: [PATCH 044/235] pre-rel 1.0.2d --- include/fix8/conjure_enum.hpp | 3 +++ include/fix8/conjure_enum_ext.hpp | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 6644f1d..df07d6e 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -302,6 +302,9 @@ class conjure_enum final : public static_only requires !std::convertible_to>; }>{}; + template + static constexpr bool is_valid() noexcept { return _is_valid(); } + static constexpr auto count() noexcept { return values.size(); } // scope ops diff --git a/include/fix8/conjure_enum_ext.hpp b/include/fix8/conjure_enum_ext.hpp index 3454e41..2897490 100644 --- a/include/fix8/conjure_enum_ext.hpp +++ b/include/fix8/conjure_enum_ext.hpp @@ -107,9 +107,6 @@ return _process_scope(scoped_entries, what); } - template - static constexpr bool is_valid() noexcept { return _is_valid(); } - // iterators static constexpr auto cbegin() noexcept { return entries.cbegin(); } static constexpr auto cend() noexcept { return entries.cend(); } From 225857eedfbf0b67c8848e161591de1114213196 Mon Sep 17 00:00:00 2001 From: David Dight Date: Mon, 12 Aug 2024 06:51:21 +1000 Subject: [PATCH 045/235] pre-rel 1.0.2d --- include/fix8/conjure_enum.hpp | 6 +++--- include/fix8/conjure_enum_ext.hpp | 7 +++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index df07d6e..f984336 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -275,9 +275,9 @@ class conjure_enum final : public static_only if constexpr (constexpr auto lc { lstr.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) return lstr.substr(cs::get_spec().size() + 2, lc - (cs::get_spec().size() + 2)); // eat "::" } - constexpr std::string_view result { _epeek_v.substr(ep + cs::get_spec().size()) }; - if constexpr (constexpr auto lc { result.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) - return result.substr(0, lc); + //constexpr std::string_view result { _epeek_v.substr(ep + cs::get_spec().size()) }; + if constexpr (constexpr auto lc { _epeek_v.substr(ep + cs::get_spec().size()).find_first_of(cs::get_spec()) }; lc != std::string_view::npos) + return _epeek_v.substr(ep + cs::get_spec().size()).substr(0, lc); else return {}; } diff --git a/include/fix8/conjure_enum_ext.hpp b/include/fix8/conjure_enum_ext.hpp index 2897490..41e4bf8 100644 --- a/include/fix8/conjure_enum_ext.hpp +++ b/include/fix8/conjure_enum_ext.hpp @@ -84,10 +84,9 @@ static constexpr std::string_view _process_scope([[maybe_unused]] const auto& entr, std::string_view what) noexcept { if constexpr (is_scoped()) - if (const auto result { std::equal_range(entr.cbegin(), - entr.cend(), scoped_tuple(what, std::string_view()), _scoped_comp) }; - result.first != result.second) - return std::get<1>(*result.first); + if (const auto result { std::equal_range(entr.cbegin(), entr.cend(), scoped_tuple(what, std::string_view()), _scoped_comp) }; + result.first != result.second) + return std::get<1>(*result.first); return what; } From 1afca876ad03cb2209ff37b36ca0965dab1579be Mon Sep 17 00:00:00 2001 From: David Dight Date: Mon, 12 Aug 2024 07:23:41 +1000 Subject: [PATCH 046/235] pre-rel 1.0.2d --- include/fix8/conjure_enum.hpp | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index f984336..11048e7 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -189,16 +189,6 @@ class conjure_enum final : public static_only static consteval const char *epeek() noexcept { return std::source_location::current().function_name(); } private: - template - static constexpr auto _enum_name() noexcept - { - constexpr auto result { _get_name() }; - return fixed_string(result); - } - - template - static constexpr auto _enum_name_v { _enum_name() }; - template static constexpr auto _entries(std::index_sequence) noexcept { @@ -275,13 +265,19 @@ class conjure_enum final : public static_only if constexpr (constexpr auto lc { lstr.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) return lstr.substr(cs::get_spec().size() + 2, lc - (cs::get_spec().size() + 2)); // eat "::" } - //constexpr std::string_view result { _epeek_v.substr(ep + cs::get_spec().size()) }; - if constexpr (constexpr auto lc { _epeek_v.substr(ep + cs::get_spec().size()).find_first_of(cs::get_spec()) }; lc != std::string_view::npos) - return _epeek_v.substr(ep + cs::get_spec().size()).substr(0, lc); + constexpr std::string_view result { _epeek_v.substr(ep + cs::get_spec().size()) }; + if constexpr (constexpr auto lc { result.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) + return result.substr(0, lc); else return {}; } + template + static constexpr auto _get_name_v { _get_name() }; + + template + static constexpr auto _enum_name_v { fixed_string<_get_name_v.size()>(_get_name_v) }; + /// comparators static constexpr bool _value_comp(const T& pl, const T& pr) noexcept { @@ -358,7 +354,7 @@ class conjure_enum final : public static_only // string <==> enum template - static constexpr std::string_view enum_to_string() noexcept { return _get_name(); } + static constexpr std::string_view enum_to_string() noexcept { return _get_name_v; } static constexpr std::string_view enum_to_string(T value, [[maybe_unused]] bool noscope=false) noexcept { From e1348dcc6ac6e4c9c9a22ee1926d2e9b9fa6c0a6 Mon Sep 17 00:00:00 2001 From: David Dight Date: Mon, 12 Aug 2024 08:10:26 +1000 Subject: [PATCH 047/235] updated --- README.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f661d74..339bfc6 100644 --- a/README.md +++ b/README.md @@ -1474,15 +1474,23 @@ enum_to_string //noscope option not available ``` These are marked ![](assets/notminimalred.svg) in the API documentation above. -## c) Class `conjure_enum` is not constructible +## c) Continous enum optimization +```c++ +#define FIX8_CONJURE_ENUM_IS_CONTINUOUS +``` +If your enum(s) are continuous (no gaps) you can enable this compiler optimization +by defining `FIX8_CONJURE_ENUM_IS_CONTINUOUS` _before_ you include `conjure_enum.hpp` +Our testing shows a reduction in overall compile times. All enums using `conjure_enum.hpp` in the current compilation unit must be continuous. + +## d) Class `conjure_enum` is not constructible All methods in this class are _static_. You cannot instantiate an object of this type. The same goes for `conjure_type`. -## d) It's not _real_ reflection +## e) It's not _real_ reflection This library provides a workaround (hack :smirk:) to current limitations of C++. There are proposals out there for future versions of the language that will provide proper reflection. See [Reflection TS](https://en.cppreference.com/w/cpp/experimental/reflect) and [Reflection for C++26](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2996r0.html) for examples of some of these. -## e) Use of `std::string_view` +## f) Use of `std::string_view` All of the generated static strings and generated static tables obtained by `std::source_location` use the library defined `fixed_string`. No string copying is done at runtime, resulting in a single static string in your application. All `conjure_enum` methods that return strings _only_ return `std::string_view`. To demonstrate this, lets look at the supplied test application `statictest`: @@ -1603,7 +1611,7 @@ $ It can be observed that there is only _one_ copy of the scoped enum value string in the executable. -## f) Compilation profiling (Clang) +## g) Compilation profiling (Clang) You can profile the compile time for Clang (other compilers TBA). Firstly install [ClangBuildAnalyzer](https://github.com/aras-p/ClangBuildAnalyzer). Then configure `conjure_enum` with: ```CMake From 1602a79f614d30bd4ee0122fbd972af3e74a126b Mon Sep 17 00:00:00 2001 From: David Dight Date: Mon, 12 Aug 2024 08:10:32 +1000 Subject: [PATCH 048/235] pre-rel 1.0.2d --- include/fix8/conjure_enum.hpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 11048e7..d7b42c3 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -189,19 +189,6 @@ class conjure_enum final : public static_only static consteval const char *epeek() noexcept { return std::source_location::current().function_name(); } private: - template - static constexpr auto _entries(std::index_sequence) noexcept - { - return std::array{{{ values[I], _enum_name_v}...}}; - } - - static constexpr auto _sorted_entries() noexcept - { - auto tmp { entries }; - std::sort(tmp.begin(), tmp.end(), _tuple_comp_rev); - return tmp; - } - template static constexpr std::string_view _epeek_v { epeek() }; @@ -278,6 +265,19 @@ class conjure_enum final : public static_only template static constexpr auto _enum_name_v { fixed_string<_get_name_v.size()>(_get_name_v) }; + template + static constexpr auto _entries(std::index_sequence) noexcept + { + return std::array{{{ values[I], _enum_name_v}...}}; + } + + static constexpr auto _sorted_entries() noexcept + { + auto tmp { entries }; + std::sort(tmp.begin(), tmp.end(), _tuple_comp_rev); + return tmp; + } + /// comparators static constexpr bool _value_comp(const T& pl, const T& pr) noexcept { @@ -299,7 +299,7 @@ class conjure_enum final : public static_only }>{}; template - static constexpr bool is_valid() noexcept { return _is_valid(); } + static constexpr bool is_valid() noexcept { return contains(); } static constexpr auto count() noexcept { return values.size(); } From 3e493692368c5f0372bdd4a853564867f1e6be7b Mon Sep 17 00:00:00 2001 From: David Dight Date: Mon, 12 Aug 2024 13:04:46 +1000 Subject: [PATCH 049/235] pre-rel 1.0.2d --- README.md | 4 ++-- include/fix8/conjure_enum.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 339bfc6..a581682 100644 --- a/README.md +++ b/README.md @@ -1474,12 +1474,12 @@ enum_to_string //noscope option not available ``` These are marked ![](assets/notminimalred.svg) in the API documentation above. -## c) Continous enum optimization +## c) Continuous enum optimization ```c++ #define FIX8_CONJURE_ENUM_IS_CONTINUOUS ``` If your enum(s) are continuous (no gaps) you can enable this compiler optimization -by defining `FIX8_CONJURE_ENUM_IS_CONTINUOUS` _before_ you include `conjure_enum.hpp` +by defining `FIX8_CONJURE_ENUM_IS_CONTINUOUS` _before_ you include `conjure_enum.hpp`. Our testing shows a reduction in overall compile times. All enums using `conjure_enum.hpp` in the current compilation unit must be continuous. ## d) Class `conjure_enum` is not constructible diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index d7b42c3..ed25c76 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -74,7 +74,7 @@ class fixed_string final { std::array _buff; template - constexpr fixed_string(std::string_view sv, std::integer_sequence) noexcept : _buff{sv[C]..., 0} {} + constexpr fixed_string(const char *pp, std::integer_sequence) noexcept : _buff{*(pp + C)..., 0} {} public: explicit constexpr fixed_string(std::string_view sv) noexcept : fixed_string{sv.data(), std::make_integer_sequence{}} {} From 787ec129f4d2ed81b742370b8ccc5c03c474a297 Mon Sep 17 00:00:00 2001 From: David Dight Date: Mon, 12 Aug 2024 13:10:28 +1000 Subject: [PATCH 050/235] pre-rel 1.0.2d --- include/fix8/conjure_enum.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index ed25c76..0721fe4 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -72,12 +72,12 @@ using namespace std::literals::string_view_literals; template class fixed_string final { - std::array _buff; + const std::array _buff; template - constexpr fixed_string(const char *pp, std::integer_sequence) noexcept : _buff{*(pp + C)..., 0} {} + constexpr fixed_string(std::string_view sv, std::integer_sequence) noexcept : _buff{sv[C]..., 0} {} public: - explicit constexpr fixed_string(std::string_view sv) noexcept : fixed_string{sv.data(), std::make_integer_sequence{}} {} + explicit constexpr fixed_string(std::string_view sv) noexcept : fixed_string{sv, std::make_integer_sequence{}} {} constexpr fixed_string() = delete; constexpr std::string_view get() const noexcept { return { _buff.data(), N }; } constexpr operator std::string_view() const noexcept { return get(); } From 1268fe150b08d446d0d6472bc5e196f5fea86938 Mon Sep 17 00:00:00 2001 From: David Dight Date: Mon, 12 Aug 2024 13:21:14 +1000 Subject: [PATCH 051/235] pre-rel 1.0.2d --- examples/cbenchmark.cpp | 1 + include/fix8/conjure_enum.hpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/examples/cbenchmark.cpp b/examples/cbenchmark.cpp index e47604b..b887537 100644 --- a/examples/cbenchmark.cpp +++ b/examples/cbenchmark.cpp @@ -35,6 +35,7 @@ #include #define FIX8_CONJURE_ENUM_MINIMAL #define FIX8_CONJURE_ENUM_IS_CONTINUOUS +#define FIX8_CONJURE_ENUM_NO_ANON #include //----------------------------------------------------------------------------------------- diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 0721fe4..1c367d4 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -241,6 +241,7 @@ class conjure_enum final : public static_only constexpr auto ep { _epeek_v.rfind(cs::get_spec()) }; if constexpr (ep == std::string_view::npos) return {}; +#if not defined FIX8_CONJURE_ENUM_NO_ANON if constexpr (_epeek_v[ep + cs::get_spec().size()] == cs::get_spec()) { #if defined __clang__ @@ -252,6 +253,7 @@ class conjure_enum final : public static_only if constexpr (constexpr auto lc { lstr.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) return lstr.substr(cs::get_spec().size() + 2, lc - (cs::get_spec().size() + 2)); // eat "::" } +#endif constexpr std::string_view result { _epeek_v.substr(ep + cs::get_spec().size()) }; if constexpr (constexpr auto lc { result.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) return result.substr(0, lc); From 9dea49e3376bbf0044be31a5af986d1306e06cf9 Mon Sep 17 00:00:00 2001 From: David Dight Date: Mon, 12 Aug 2024 14:27:02 +1000 Subject: [PATCH 052/235] pre-rel 1.0.2d --- examples/cbenchmark.cpp | 4 +--- include/fix8/conjure_enum.hpp | 11 +++++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/examples/cbenchmark.cpp b/examples/cbenchmark.cpp index b887537..6325242 100644 --- a/examples/cbenchmark.cpp +++ b/examples/cbenchmark.cpp @@ -33,9 +33,7 @@ // cl /nologo /MD /std:c++latest /Bt+ /I ..\include ..\examples\cbenchmark.cpp|find "c1xx.dll" //---------------------------------------------------------------------------------------- #include -#define FIX8_CONJURE_ENUM_MINIMAL -#define FIX8_CONJURE_ENUM_IS_CONTINUOUS -#define FIX8_CONJURE_ENUM_NO_ANON +#define FIX8_CONJURE_ENUM_ALL_OPTIMIZATIONS #include //----------------------------------------------------------------------------------------- diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 1c367d4..5f7c216 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -47,6 +47,17 @@ #include #include #include +#if defined FIX8_CONJURE_ENUM_ALL_OPTIMIZATIONS +# if not defined FIX8_CONJURE_ENUM_IS_CONTINUOUS +# define FIX8_CONJURE_ENUM_IS_CONTINUOUS +# endif +# if not defined FIX8_CONJURE_ENUM_NO_ANON +# define FIX8_CONJURE_ENUM_NO_ANON +# endif +# if not defined FIX8_CONJURE_ENUM_MINIMAL +# define FIX8_CONJURE_ENUM_MINIMAL +# endif +#endif #if not defined FIX8_CONJURE_ENUM_MINIMAL # include #endif From 8dc4015e8ccfcc4d894570ab8f4b5bdc2b8e390b Mon Sep 17 00:00:00 2001 From: David Dight Date: Tue, 13 Aug 2024 06:26:59 +1000 Subject: [PATCH 053/235] pre-rel 1.0.2d --- include/fix8/conjure_enum.hpp | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 5f7c216..8e322ce 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -41,12 +41,6 @@ #endif //---------------------------------------------------------------------------------------- -#include -#include -#include -#include -#include -#include #if defined FIX8_CONJURE_ENUM_ALL_OPTIMIZATIONS # if not defined FIX8_CONJURE_ENUM_IS_CONTINUOUS # define FIX8_CONJURE_ENUM_IS_CONTINUOUS @@ -58,11 +52,18 @@ # define FIX8_CONJURE_ENUM_MINIMAL # endif #endif + +//----------------------------------------------------------------------------------------- +#include +#include +#include +#include +#include +#include +#include #if not defined FIX8_CONJURE_ENUM_MINIMAL # include #endif -//#include -#include //----------------------------------------------------------------------------------------- namespace FIX8 { @@ -213,8 +214,10 @@ class conjure_enum final : public static_only { if constexpr (_epeek_v[ep + cs::get_spec().size() + 1] == '(') return false; +#if not defined FIX8_CONJURE_ENUM_NO_ANON if constexpr (_epeek_v.find(cs::get_spec(), ep + cs::get_spec().size()) != std::string_view::npos) // is anon return true; +#endif } else if constexpr (_epeek_v.find_first_of(cs::get_spec(), ep + cs::get_spec().size()) != std::string_view::npos) return true; @@ -294,15 +297,19 @@ class conjure_enum final : public static_only /// comparators static constexpr bool _value_comp(const T& pl, const T& pr) noexcept { - return static_cast(pl) < static_cast(pr); + return pl < pr; } static constexpr bool _tuple_comp(const enum_tuple& pl, const enum_tuple& pr) noexcept { - return static_cast(std::get(pl)) < static_cast(std::get(pr)); + const auto& [l1,l2] { pl }; + const auto& [r1,r2] { pr }; + return l1 < r1; } static constexpr bool _tuple_comp_rev(const enum_tuple& pl, const enum_tuple& pr) noexcept { - return std::get(pl) < std::get(pr); + const auto& [l1,l2] { pl }; + const auto& [r1,r2] { pr }; + return l2 < r2; } public: From fe343248a65945e40d54f248b946e38f6cc9094a Mon Sep 17 00:00:00 2001 From: David Dight Date: Tue, 13 Aug 2024 06:27:58 +1000 Subject: [PATCH 054/235] pre-rel 1.0.2d --- include/fix8/conjure_enum.hpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 8e322ce..e2909d5 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -297,19 +297,15 @@ class conjure_enum final : public static_only /// comparators static constexpr bool _value_comp(const T& pl, const T& pr) noexcept { - return pl < pr; + return static_cast(pl) < static_cast(pr); } static constexpr bool _tuple_comp(const enum_tuple& pl, const enum_tuple& pr) noexcept { - const auto& [l1,l2] { pl }; - const auto& [r1,r2] { pr }; - return l1 < r1; + return static_cast(std::get(pl)) < static_cast(std::get(pr)); } static constexpr bool _tuple_comp_rev(const enum_tuple& pl, const enum_tuple& pr) noexcept { - const auto& [l1,l2] { pl }; - const auto& [r1,r2] { pr }; - return l2 < r2; + return std::get(pl) < std::get(pr); } public: From 789194f60fd613c55b89de3ebba98f1161d4fbb8 Mon Sep 17 00:00:00 2001 From: David Dight Date: Tue, 13 Aug 2024 06:35:49 +1000 Subject: [PATCH 055/235] updated --- README.md | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a581682..9291a3e 100644 --- a/README.md +++ b/README.md @@ -1482,15 +1482,35 @@ If your enum(s) are continuous (no gaps) you can enable this compiler optimizati by defining `FIX8_CONJURE_ENUM_IS_CONTINUOUS` _before_ you include `conjure_enum.hpp`. Our testing shows a reduction in overall compile times. All enums using `conjure_enum.hpp` in the current compilation unit must be continuous. -## d) Class `conjure_enum` is not constructible +## d) Anonymous enum optimization +```c++ +#define FIX8_CONJURE_ENUM_NO_ANON +``` +If your enum(s) are not within any anonymous namespaces (rarely used for this purpose), you can enable this compiler optimization +by defining `FIX8_CONJURE_ENUM_NO_ANON` _before_ you include `conjure_enum.hpp`. +Our testing shows a reduction in overall compile times. All enums using `conjure_enum.hpp` in the current compilation unit must be continuous. + +## e) Enable all optimizations +```c++ +#define FIX8_CONJURE_ENUM_ALL_OPTIMIZATIONS +``` +You can enable all optimizations described above by defining `FIX8_CONJURE_ENUM_ALL_OPTIMIZATIONS` _before_ you include `conjure_enum.hpp`. +This will is the equivalent of defining: +```c++ +#define FIX8_CONJURE_ENUM_MINIMAL +#define FIX8_CONJURE_ENUM_IS_CONTINUOUS +#define FIX8_CONJURE_ENUM_NO_ANON +``` + +## f) Class `conjure_enum` is not constructible All methods in this class are _static_. You cannot instantiate an object of this type. The same goes for `conjure_type`. -## e) It's not _real_ reflection +## g) It's not _real_ reflection This library provides a workaround (hack :smirk:) to current limitations of C++. There are proposals out there for future versions of the language that will provide proper reflection. See [Reflection TS](https://en.cppreference.com/w/cpp/experimental/reflect) and [Reflection for C++26](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2996r0.html) for examples of some of these. -## f) Use of `std::string_view` +## h) Use of `std::string_view` All of the generated static strings and generated static tables obtained by `std::source_location` use the library defined `fixed_string`. No string copying is done at runtime, resulting in a single static string in your application. All `conjure_enum` methods that return strings _only_ return `std::string_view`. To demonstrate this, lets look at the supplied test application `statictest`: @@ -1611,7 +1631,7 @@ $ It can be observed that there is only _one_ copy of the scoped enum value string in the executable. -## g) Compilation profiling (Clang) +## i) Compilation profiling (Clang) You can profile the compile time for Clang (other compilers TBA). Firstly install [ClangBuildAnalyzer](https://github.com/aras-p/ClangBuildAnalyzer). Then configure `conjure_enum` with: ```CMake From ef927eadb8ff91ff88351c2b81c51c240c7096cb Mon Sep 17 00:00:00 2001 From: David Dight Date: Tue, 13 Aug 2024 07:05:00 +1000 Subject: [PATCH 056/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9291a3e..4a50de5 100644 --- a/README.md +++ b/README.md @@ -1495,7 +1495,7 @@ Our testing shows a reduction in overall compile times. All enums using `conjure #define FIX8_CONJURE_ENUM_ALL_OPTIMIZATIONS ``` You can enable all optimizations described above by defining `FIX8_CONJURE_ENUM_ALL_OPTIMIZATIONS` _before_ you include `conjure_enum.hpp`. -This will is the equivalent of defining: +This is the equivalent of defining: ```c++ #define FIX8_CONJURE_ENUM_MINIMAL #define FIX8_CONJURE_ENUM_IS_CONTINUOUS From fb46f66351a42c646e4e46c4247beafbc25498c2 Mon Sep 17 00:00:00 2001 From: David Dight Date: Tue, 13 Aug 2024 07:05:06 +1000 Subject: [PATCH 057/235] pre-rel 1.0.2d --- include/fix8/conjure_enum.hpp | 4 ++-- include/fix8/conjure_enum_ext.hpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index e2909d5..a15d432 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -297,11 +297,11 @@ class conjure_enum final : public static_only /// comparators static constexpr bool _value_comp(const T& pl, const T& pr) noexcept { - return static_cast(pl) < static_cast(pr); + return pl < pr; } static constexpr bool _tuple_comp(const enum_tuple& pl, const enum_tuple& pr) noexcept { - return static_cast(std::get(pl)) < static_cast(std::get(pr)); + return std::get(pl) < std::get(pr); } static constexpr bool _tuple_comp_rev(const enum_tuple& pl, const enum_tuple& pr) noexcept { diff --git a/include/fix8/conjure_enum_ext.hpp b/include/fix8/conjure_enum_ext.hpp index 41e4bf8..1395ee8 100644 --- a/include/fix8/conjure_enum_ext.hpp +++ b/include/fix8/conjure_enum_ext.hpp @@ -31,7 +31,7 @@ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. //---------------------------------------------------------------------------------------- -// Full build include fragment +// Full build include fragment; do not include separately //---------------------------------------------------------------------------------------- #ifndef FIX8_CONJURE_ENUM_EXT_HPP_ #define FIX8_CONJURE_ENUM_EXT_HPP_ @@ -187,7 +187,7 @@ template static constexpr bool tuple_comp(const std::tuple& pl, const std::tuple& pr) noexcept { - return static_cast(std::get(pl)) < static_cast(std::get(pr)); + return std::get(pl) < std::get(pr); } template // with not found value(nval) for return From 2a287e464c91f12112a8c78671ad47cf3979ee73 Mon Sep 17 00:00:00 2001 From: David Dight Date: Tue, 13 Aug 2024 08:53:52 +1000 Subject: [PATCH 058/235] pre-rel 1.0.2d --- include/fix8/conjure_enum.hpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index a15d432..434d0ff 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -374,22 +374,21 @@ class conjure_enum final : public static_only static constexpr std::string_view enum_to_string(T value, [[maybe_unused]] bool noscope=false) noexcept { - if (const auto result { std::equal_range(entries.cbegin(), entries.cend(), enum_tuple(value, std::string_view()), _tuple_comp) }; - result.first != result.second) + if (const auto [begin,end] { std::equal_range(entries.cbegin(), entries.cend(), enum_tuple(value, std::string_view()), _tuple_comp) }; + begin != end) { #if not defined FIX8_CONJURE_ENUM_MINIMAL if (noscope) - return remove_scope(std::get(*result.first)); + return remove_scope(std::get(*begin)); #endif - return std::get(*result.first); + return std::get(*begin); } return {}; } static constexpr std::optional string_to_enum(std::string_view str) noexcept { - if (const auto result { std::equal_range(sorted_entries.cbegin(), sorted_entries.cend(), enum_tuple(T{}, str), _tuple_comp_rev) }; - result.first != result.second) - return std::get(*result.first); + if (const auto [begin,end] { std::equal_range(sorted_entries.cbegin(), sorted_entries.cend(), enum_tuple(T{}, str), _tuple_comp_rev) }; begin != end) + return std::get(*begin); return {}; } From a50d16e89c286946a29ea981aa5d673d0712e00d Mon Sep 17 00:00:00 2001 From: David Dight Date: Tue, 13 Aug 2024 09:05:13 +1000 Subject: [PATCH 059/235] pre-rel 1.0.2d --- include/fix8/conjure_enum.hpp | 17 +++++++---------- include/fix8/conjure_enum_ext.hpp | 28 +++++++++++++--------------- 2 files changed, 20 insertions(+), 25 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 434d0ff..6fd8106 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -339,19 +339,17 @@ class conjure_enum final : public static_only } static constexpr std::optional int_to_enum(int value) noexcept { - if (const auto result { std::equal_range(values.cbegin(), values.cend(), static_cast(value), _value_comp) }; - result.first != result.second) - return *result.first; + if (const auto [begin,end] { std::equal_range(values.cbegin(), values.cend(), static_cast(value), _value_comp) }; + begin != end) + return *begin; return {}; } // index static constexpr std::optional index(T value) noexcept { - if (const auto result { std::equal_range(values.cbegin(), values.cend(), value, _value_comp) }; - result.first != result.second) - return &*result.first - &*values.cbegin(); - return {}; + const auto [begin,end] { std::equal_range(entries.cbegin(), entries.cend(), enum_tuple(value, std::string_view()), _tuple_comp) }; + return begin != end ? &*begin - &*entries.cbegin() : std::optional{}; } template static constexpr std::optional index() noexcept { return index(e); } @@ -387,9 +385,8 @@ class conjure_enum final : public static_only } static constexpr std::optional string_to_enum(std::string_view str) noexcept { - if (const auto [begin,end] { std::equal_range(sorted_entries.cbegin(), sorted_entries.cend(), enum_tuple(T{}, str), _tuple_comp_rev) }; begin != end) - return std::get(*begin); - return {}; + const auto [begin,end] { std::equal_range(sorted_entries.cbegin(), sorted_entries.cend(), enum_tuple(T{}, str), _tuple_comp_rev) }; + return begin != end ? std::get(*begin) : std::optional{}; } // public constexpr data structures diff --git a/include/fix8/conjure_enum_ext.hpp b/include/fix8/conjure_enum_ext.hpp index 1395ee8..7b980c2 100644 --- a/include/fix8/conjure_enum_ext.hpp +++ b/include/fix8/conjure_enum_ext.hpp @@ -84,9 +84,9 @@ static constexpr std::string_view _process_scope([[maybe_unused]] const auto& entr, std::string_view what) noexcept { if constexpr (is_scoped()) - if (const auto result { std::equal_range(entr.cbegin(), entr.cend(), scoped_tuple(what, std::string_view()), _scoped_comp) }; - result.first != result.second) - return std::get<1>(*result.first); + if (const auto [begin,end] { std::equal_range(entr.cbegin(), entr.cend(), scoped_tuple(what, std::string_view()), _scoped_comp) }; + begin != end) + return std::get<1>(*begin); return what; } @@ -115,10 +115,8 @@ static constexpr auto back() noexcept { return *std::prev(cend()); } static constexpr std::optional unscoped_string_to_enum(std::string_view str) noexcept { - if (const auto result { std::equal_range(unscoped_entries.cbegin(), unscoped_entries.cend(), enum_tuple(T{}, str), _tuple_comp_rev) }; - result.first != result.second) - return std::get(*result.first); - return {}; + const auto [begin,end] { std::equal_range(unscoped_entries.cbegin(), unscoped_entries.cend(), enum_tuple(T{}, str), _tuple_comp_rev) }; + return begin != end ? std::get(*begin) : std::optional{}; } static constexpr std::string_view type_name() noexcept @@ -194,24 +192,24 @@ requires std::invocable [[maybe_unused]] static constexpr R dispatch(T ev, R nval, const std::array, I>& disp, Args&&... args) noexcept { - const auto result { std::equal_range(disp.cbegin(), disp.cend(), std::make_tuple(ev, Fn()), tuple_comp) }; - return result.first != result.second ? std::invoke(std::get(*result.first), ev, std::forward(args)...) : nval; + const auto [begin,end] { std::equal_range(disp.cbegin(), disp.cend(), std::make_tuple(ev, Fn()), tuple_comp) }; + return begin != end ? std::invoke(std::get(*begin), ev, std::forward(args)...) : nval; } template // specialisation for member function with not found value(nval) for return requires std::invocable [[maybe_unused]] static constexpr R dispatch(T ev, R nval, const std::array, I>& disp, C *obj, Args&&... args) noexcept { - const auto result { std::equal_range(disp.cbegin(), disp.cend(), std::make_tuple(ev, Fn()), tuple_comp) }; - return result.first != result.second ? std::invoke(std::get(*result.first), obj, ev, std::forward(args)...) : nval; + const auto [begin,end] { std::equal_range(disp.cbegin(), disp.cend(), std::make_tuple(ev, Fn()), tuple_comp) }; + return begin != end ? std::invoke(std::get(*begin), obj, ev, std::forward(args)...) : nval; } template // void func with not found call to last element requires (std::invocable && I > 0) static constexpr void dispatch(T ev, const std::array, I>& disp, Args&&... args) noexcept { - const auto result { std::equal_range(disp.cbegin(), std::prev(disp.cend()), std::make_tuple(ev, Fn()), tuple_comp) }; - return result.first != result.second ? std::invoke(std::get(*result.first), ev, std::forward(args)...) + const auto [begin,end] { std::equal_range(disp.cbegin(), std::prev(disp.cend()), std::make_tuple(ev, Fn()), tuple_comp) }; + return begin != end ? std::invoke(std::get(*begin), ev, std::forward(args)...) : std::invoke(std::get(*std::prev(disp.cend())), ev, std::forward(args)...); } @@ -219,8 +217,8 @@ requires (std::invocable && I > 0) static constexpr void dispatch(T ev, const std::array, I>& disp, C *obj, Args&&... args) noexcept { - const auto result { std::equal_range(disp.cbegin(), std::prev(disp.cend()), std::make_tuple(ev, Fn()), tuple_comp) }; - return result.first != result.second ? std::invoke(std::get(*result.first), obj, ev, std::forward(args)...) + const auto [begin,end] { std::equal_range(disp.cbegin(), std::prev(disp.cend()), std::make_tuple(ev, Fn()), tuple_comp) }; + return begin != end ? std::invoke(std::get(*begin), obj, ev, std::forward(args)...) : std::invoke(std::get(*std::prev(disp.cend())), obj, ev, std::forward(args)...); } From c7a5161dc4832e5b04cb0ab2bfc9af5fa28fce09 Mon Sep 17 00:00:00 2001 From: David Dight Date: Tue, 13 Aug 2024 09:06:23 +1000 Subject: [PATCH 060/235] pre-rel 1.0.2d --- include/fix8/conjure_enum.hpp | 26 +++++++++++++++----------- include/fix8/conjure_enum_ext.hpp | 28 +++++++++++++++------------- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 6fd8106..a15d432 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -339,17 +339,19 @@ class conjure_enum final : public static_only } static constexpr std::optional int_to_enum(int value) noexcept { - if (const auto [begin,end] { std::equal_range(values.cbegin(), values.cend(), static_cast(value), _value_comp) }; - begin != end) - return *begin; + if (const auto result { std::equal_range(values.cbegin(), values.cend(), static_cast(value), _value_comp) }; + result.first != result.second) + return *result.first; return {}; } // index static constexpr std::optional index(T value) noexcept { - const auto [begin,end] { std::equal_range(entries.cbegin(), entries.cend(), enum_tuple(value, std::string_view()), _tuple_comp) }; - return begin != end ? &*begin - &*entries.cbegin() : std::optional{}; + if (const auto result { std::equal_range(values.cbegin(), values.cend(), value, _value_comp) }; + result.first != result.second) + return &*result.first - &*values.cbegin(); + return {}; } template static constexpr std::optional index() noexcept { return index(e); } @@ -372,21 +374,23 @@ class conjure_enum final : public static_only static constexpr std::string_view enum_to_string(T value, [[maybe_unused]] bool noscope=false) noexcept { - if (const auto [begin,end] { std::equal_range(entries.cbegin(), entries.cend(), enum_tuple(value, std::string_view()), _tuple_comp) }; - begin != end) + if (const auto result { std::equal_range(entries.cbegin(), entries.cend(), enum_tuple(value, std::string_view()), _tuple_comp) }; + result.first != result.second) { #if not defined FIX8_CONJURE_ENUM_MINIMAL if (noscope) - return remove_scope(std::get(*begin)); + return remove_scope(std::get(*result.first)); #endif - return std::get(*begin); + return std::get(*result.first); } return {}; } static constexpr std::optional string_to_enum(std::string_view str) noexcept { - const auto [begin,end] { std::equal_range(sorted_entries.cbegin(), sorted_entries.cend(), enum_tuple(T{}, str), _tuple_comp_rev) }; - return begin != end ? std::get(*begin) : std::optional{}; + if (const auto result { std::equal_range(sorted_entries.cbegin(), sorted_entries.cend(), enum_tuple(T{}, str), _tuple_comp_rev) }; + result.first != result.second) + return std::get(*result.first); + return {}; } // public constexpr data structures diff --git a/include/fix8/conjure_enum_ext.hpp b/include/fix8/conjure_enum_ext.hpp index 7b980c2..1395ee8 100644 --- a/include/fix8/conjure_enum_ext.hpp +++ b/include/fix8/conjure_enum_ext.hpp @@ -84,9 +84,9 @@ static constexpr std::string_view _process_scope([[maybe_unused]] const auto& entr, std::string_view what) noexcept { if constexpr (is_scoped()) - if (const auto [begin,end] { std::equal_range(entr.cbegin(), entr.cend(), scoped_tuple(what, std::string_view()), _scoped_comp) }; - begin != end) - return std::get<1>(*begin); + if (const auto result { std::equal_range(entr.cbegin(), entr.cend(), scoped_tuple(what, std::string_view()), _scoped_comp) }; + result.first != result.second) + return std::get<1>(*result.first); return what; } @@ -115,8 +115,10 @@ static constexpr auto back() noexcept { return *std::prev(cend()); } static constexpr std::optional unscoped_string_to_enum(std::string_view str) noexcept { - const auto [begin,end] { std::equal_range(unscoped_entries.cbegin(), unscoped_entries.cend(), enum_tuple(T{}, str), _tuple_comp_rev) }; - return begin != end ? std::get(*begin) : std::optional{}; + if (const auto result { std::equal_range(unscoped_entries.cbegin(), unscoped_entries.cend(), enum_tuple(T{}, str), _tuple_comp_rev) }; + result.first != result.second) + return std::get(*result.first); + return {}; } static constexpr std::string_view type_name() noexcept @@ -192,24 +194,24 @@ requires std::invocable [[maybe_unused]] static constexpr R dispatch(T ev, R nval, const std::array, I>& disp, Args&&... args) noexcept { - const auto [begin,end] { std::equal_range(disp.cbegin(), disp.cend(), std::make_tuple(ev, Fn()), tuple_comp) }; - return begin != end ? std::invoke(std::get(*begin), ev, std::forward(args)...) : nval; + const auto result { std::equal_range(disp.cbegin(), disp.cend(), std::make_tuple(ev, Fn()), tuple_comp) }; + return result.first != result.second ? std::invoke(std::get(*result.first), ev, std::forward(args)...) : nval; } template // specialisation for member function with not found value(nval) for return requires std::invocable [[maybe_unused]] static constexpr R dispatch(T ev, R nval, const std::array, I>& disp, C *obj, Args&&... args) noexcept { - const auto [begin,end] { std::equal_range(disp.cbegin(), disp.cend(), std::make_tuple(ev, Fn()), tuple_comp) }; - return begin != end ? std::invoke(std::get(*begin), obj, ev, std::forward(args)...) : nval; + const auto result { std::equal_range(disp.cbegin(), disp.cend(), std::make_tuple(ev, Fn()), tuple_comp) }; + return result.first != result.second ? std::invoke(std::get(*result.first), obj, ev, std::forward(args)...) : nval; } template // void func with not found call to last element requires (std::invocable && I > 0) static constexpr void dispatch(T ev, const std::array, I>& disp, Args&&... args) noexcept { - const auto [begin,end] { std::equal_range(disp.cbegin(), std::prev(disp.cend()), std::make_tuple(ev, Fn()), tuple_comp) }; - return begin != end ? std::invoke(std::get(*begin), ev, std::forward(args)...) + const auto result { std::equal_range(disp.cbegin(), std::prev(disp.cend()), std::make_tuple(ev, Fn()), tuple_comp) }; + return result.first != result.second ? std::invoke(std::get(*result.first), ev, std::forward(args)...) : std::invoke(std::get(*std::prev(disp.cend())), ev, std::forward(args)...); } @@ -217,8 +219,8 @@ requires (std::invocable && I > 0) static constexpr void dispatch(T ev, const std::array, I>& disp, C *obj, Args&&... args) noexcept { - const auto [begin,end] { std::equal_range(disp.cbegin(), std::prev(disp.cend()), std::make_tuple(ev, Fn()), tuple_comp) }; - return begin != end ? std::invoke(std::get(*begin), obj, ev, std::forward(args)...) + const auto result { std::equal_range(disp.cbegin(), std::prev(disp.cend()), std::make_tuple(ev, Fn()), tuple_comp) }; + return result.first != result.second ? std::invoke(std::get(*result.first), obj, ev, std::forward(args)...) : std::invoke(std::get(*std::prev(disp.cend())), obj, ev, std::forward(args)...); } From 053c79ca5aeb656171cf1f10b82e8c454fe4b62d Mon Sep 17 00:00:00 2001 From: David Dight Date: Tue, 13 Aug 2024 10:57:06 +1000 Subject: [PATCH 061/235] pre-rel 1.0.2d --- examples/cbenchmark.cpp | 3 +- include/fix8/conjure_enum.hpp | 109 +++++++++++++++--------------- include/fix8/conjure_enum_ext.hpp | 28 ++++---- 3 files changed, 70 insertions(+), 70 deletions(-) diff --git a/examples/cbenchmark.cpp b/examples/cbenchmark.cpp index 6325242..e432102 100644 --- a/examples/cbenchmark.cpp +++ b/examples/cbenchmark.cpp @@ -33,11 +33,12 @@ // cl /nologo /MD /std:c++latest /Bt+ /I ..\include ..\examples\cbenchmark.cpp|find "c1xx.dll" //---------------------------------------------------------------------------------------- #include -#define FIX8_CONJURE_ENUM_ALL_OPTIMIZATIONS +#define FIX8_CONJURE_ENUM_MINIMAL #include //----------------------------------------------------------------------------------------- FIX8_CONJURE_ENUM_SET_RANGE_INTS(std::errc, 0, 71) +FIX8_CONJURE_ENUM_SET_FLAGS(std::errc,true,true) int test_conjure_enum(std::errc err) { diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index a15d432..46b2ff9 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -41,19 +41,6 @@ #endif //---------------------------------------------------------------------------------------- -#if defined FIX8_CONJURE_ENUM_ALL_OPTIMIZATIONS -# if not defined FIX8_CONJURE_ENUM_IS_CONTINUOUS -# define FIX8_CONJURE_ENUM_IS_CONTINUOUS -# endif -# if not defined FIX8_CONJURE_ENUM_NO_ANON -# define FIX8_CONJURE_ENUM_NO_ANON -# endif -# if not defined FIX8_CONJURE_ENUM_MINIMAL -# define FIX8_CONJURE_ENUM_MINIMAL -# endif -#endif - -//----------------------------------------------------------------------------------------- #include #include #include @@ -183,6 +170,21 @@ struct enum_range final : public static_only #define FIX8_CONJURE_ENUM_SET_RANGE(minv,maxv) \ FIX8_CONJURE_ENUM_SET_RANGE_INTS(decltype(minv),static_cast(minv), static_cast(maxv)) +//----------------------------------------------------------------------------------------- +// You can specialise this class to define custom flags for your enum +//----------------------------------------------------------------------------------------- +template +struct enum_flags final : public static_only +{ + static constexpr bool is_continuous{}, no_anon{}; +}; + +//----------------------------------------------------------------------------------------- +// Convenience macros for above +//----------------------------------------------------------------------------------------- +#define FIX8_CONJURE_ENUM_SET_FLAGS(ec,iscont,noanon) \ + template<> struct FIX8::enum_flags { static constexpr int is_continuous{iscont}, no_anon{noanon}; }; + //----------------------------------------------------------------------------------------- template class conjure_enum final : public static_only @@ -214,10 +216,9 @@ class conjure_enum final : public static_only { if constexpr (_epeek_v[ep + cs::get_spec().size() + 1] == '(') return false; -#if not defined FIX8_CONJURE_ENUM_NO_ANON - if constexpr (_epeek_v.find(cs::get_spec(), ep + cs::get_spec().size()) != std::string_view::npos) // is anon - return true; -#endif + if constexpr (!enum_flags::no_anon) + if constexpr (_epeek_v.find(cs::get_spec(), ep + cs::get_spec().size()) != std::string_view::npos) // is anon + return true; } else if constexpr (_epeek_v.find_first_of(cs::get_spec(), ep + cs::get_spec().size()) != std::string_view::npos) return true; @@ -234,19 +235,22 @@ class conjure_enum final : public static_only template static constexpr auto _values(std::index_sequence) noexcept { -#if defined FIX8_CONJURE_ENUM_IS_CONTINUOUS - static_assert(sizeof...(I) > 0, "conjure_enum requires non-empty enum"); - return std::array{static_cast(enum_min_value + I)... }; -#else - constexpr std::array valid { _is_valid(enum_min_value + I)>()... }; - constexpr auto valid_cnt { std::count_if(valid.cbegin(), valid.cend(), [](bool val) noexcept { return val; }) }; - static_assert(valid_cnt > 0, "conjure_enum requires non-empty enum"); - std::array vals{}; - for(std::size_t idx{}, nn{}; nn < valid_cnt; ++idx) - if (valid[idx]) - vals[nn++] = static_cast(enum_min_value + idx); - return vals; -#endif + if constexpr (enum_flags::is_continuous) + { + static_assert(sizeof...(I) > 0, "conjure_enum requires non-empty enum"); + return std::array{static_cast(enum_min_value + I)... }; + } + else + { + constexpr std::array valid { _is_valid(enum_min_value + I)>()... }; + constexpr auto valid_cnt { std::count_if(valid.cbegin(), valid.cend(), [](bool val) noexcept { return val; }) }; + static_assert(valid_cnt > 0, "conjure_enum requires non-empty enum"); + std::array vals{}; + for(std::size_t idx{}, nn{}; nn < valid_cnt; ++idx) + if (valid[idx]) + vals[nn++] = static_cast(enum_min_value + idx); + return vals; + } } template @@ -255,19 +259,20 @@ class conjure_enum final : public static_only constexpr auto ep { _epeek_v.rfind(cs::get_spec()) }; if constexpr (ep == std::string_view::npos) return {}; -#if not defined FIX8_CONJURE_ENUM_NO_ANON - if constexpr (_epeek_v[ep + cs::get_spec().size()] == cs::get_spec()) + if constexpr (!enum_flags::no_anon) { + if constexpr (_epeek_v[ep + cs::get_spec().size()] == cs::get_spec()) + { #if defined __clang__ - if constexpr (_epeek_v[ep + cs::get_spec().size() + 1] == cs::get_spec()) - return {}; + if constexpr (_epeek_v[ep + cs::get_spec().size() + 1] == cs::get_spec()) + return {}; #endif - if (constexpr auto lstr { _epeek_v.substr(ep + cs::get_spec().size()) }; - lstr.find(cs::get_spec()) != std::string_view::npos) // is anon - if constexpr (constexpr auto lc { lstr.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) - return lstr.substr(cs::get_spec().size() + 2, lc - (cs::get_spec().size() + 2)); // eat "::" + if (constexpr auto lstr { _epeek_v.substr(ep + cs::get_spec().size()) }; + lstr.find(cs::get_spec()) != std::string_view::npos) // is anon + if constexpr (constexpr auto lc { lstr.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) + return lstr.substr(cs::get_spec().size() + 2, lc - (cs::get_spec().size() + 2)); // eat "::" + } } -#endif constexpr std::string_view result { _epeek_v.substr(ep + cs::get_spec().size()) }; if constexpr (constexpr auto lc { result.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) return result.substr(0, lc); @@ -339,19 +344,17 @@ class conjure_enum final : public static_only } static constexpr std::optional int_to_enum(int value) noexcept { - if (const auto result { std::equal_range(values.cbegin(), values.cend(), static_cast(value), _value_comp) }; - result.first != result.second) - return *result.first; + if (const auto [begin,end] { std::equal_range(values.cbegin(), values.cend(), static_cast(value), _value_comp) }; + begin != end) + return *begin; return {}; } // index static constexpr std::optional index(T value) noexcept { - if (const auto result { std::equal_range(values.cbegin(), values.cend(), value, _value_comp) }; - result.first != result.second) - return &*result.first - &*values.cbegin(); - return {}; + const auto [begin,end] { std::equal_range(entries.cbegin(), entries.cend(), enum_tuple(value, std::string_view()), _tuple_comp) }; + return begin != end ? &*begin - &*entries.cbegin() : std::optional{}; } template static constexpr std::optional index() noexcept { return index(e); } @@ -374,23 +377,21 @@ class conjure_enum final : public static_only static constexpr std::string_view enum_to_string(T value, [[maybe_unused]] bool noscope=false) noexcept { - if (const auto result { std::equal_range(entries.cbegin(), entries.cend(), enum_tuple(value, std::string_view()), _tuple_comp) }; - result.first != result.second) + if (const auto [begin,end] { std::equal_range(entries.cbegin(), entries.cend(), enum_tuple(value, std::string_view()), _tuple_comp) }; + begin != end) { #if not defined FIX8_CONJURE_ENUM_MINIMAL if (noscope) - return remove_scope(std::get(*result.first)); + return remove_scope(std::get(*begin)); #endif - return std::get(*result.first); + return std::get(*begin); } return {}; } static constexpr std::optional string_to_enum(std::string_view str) noexcept { - if (const auto result { std::equal_range(sorted_entries.cbegin(), sorted_entries.cend(), enum_tuple(T{}, str), _tuple_comp_rev) }; - result.first != result.second) - return std::get(*result.first); - return {}; + const auto [begin,end] { std::equal_range(sorted_entries.cbegin(), sorted_entries.cend(), enum_tuple(T{}, str), _tuple_comp_rev) }; + return begin != end ? std::get(*begin) : std::optional{}; } // public constexpr data structures diff --git a/include/fix8/conjure_enum_ext.hpp b/include/fix8/conjure_enum_ext.hpp index 1395ee8..7b980c2 100644 --- a/include/fix8/conjure_enum_ext.hpp +++ b/include/fix8/conjure_enum_ext.hpp @@ -84,9 +84,9 @@ static constexpr std::string_view _process_scope([[maybe_unused]] const auto& entr, std::string_view what) noexcept { if constexpr (is_scoped()) - if (const auto result { std::equal_range(entr.cbegin(), entr.cend(), scoped_tuple(what, std::string_view()), _scoped_comp) }; - result.first != result.second) - return std::get<1>(*result.first); + if (const auto [begin,end] { std::equal_range(entr.cbegin(), entr.cend(), scoped_tuple(what, std::string_view()), _scoped_comp) }; + begin != end) + return std::get<1>(*begin); return what; } @@ -115,10 +115,8 @@ static constexpr auto back() noexcept { return *std::prev(cend()); } static constexpr std::optional unscoped_string_to_enum(std::string_view str) noexcept { - if (const auto result { std::equal_range(unscoped_entries.cbegin(), unscoped_entries.cend(), enum_tuple(T{}, str), _tuple_comp_rev) }; - result.first != result.second) - return std::get(*result.first); - return {}; + const auto [begin,end] { std::equal_range(unscoped_entries.cbegin(), unscoped_entries.cend(), enum_tuple(T{}, str), _tuple_comp_rev) }; + return begin != end ? std::get(*begin) : std::optional{}; } static constexpr std::string_view type_name() noexcept @@ -194,24 +192,24 @@ requires std::invocable [[maybe_unused]] static constexpr R dispatch(T ev, R nval, const std::array, I>& disp, Args&&... args) noexcept { - const auto result { std::equal_range(disp.cbegin(), disp.cend(), std::make_tuple(ev, Fn()), tuple_comp) }; - return result.first != result.second ? std::invoke(std::get(*result.first), ev, std::forward(args)...) : nval; + const auto [begin,end] { std::equal_range(disp.cbegin(), disp.cend(), std::make_tuple(ev, Fn()), tuple_comp) }; + return begin != end ? std::invoke(std::get(*begin), ev, std::forward(args)...) : nval; } template // specialisation for member function with not found value(nval) for return requires std::invocable [[maybe_unused]] static constexpr R dispatch(T ev, R nval, const std::array, I>& disp, C *obj, Args&&... args) noexcept { - const auto result { std::equal_range(disp.cbegin(), disp.cend(), std::make_tuple(ev, Fn()), tuple_comp) }; - return result.first != result.second ? std::invoke(std::get(*result.first), obj, ev, std::forward(args)...) : nval; + const auto [begin,end] { std::equal_range(disp.cbegin(), disp.cend(), std::make_tuple(ev, Fn()), tuple_comp) }; + return begin != end ? std::invoke(std::get(*begin), obj, ev, std::forward(args)...) : nval; } template // void func with not found call to last element requires (std::invocable && I > 0) static constexpr void dispatch(T ev, const std::array, I>& disp, Args&&... args) noexcept { - const auto result { std::equal_range(disp.cbegin(), std::prev(disp.cend()), std::make_tuple(ev, Fn()), tuple_comp) }; - return result.first != result.second ? std::invoke(std::get(*result.first), ev, std::forward(args)...) + const auto [begin,end] { std::equal_range(disp.cbegin(), std::prev(disp.cend()), std::make_tuple(ev, Fn()), tuple_comp) }; + return begin != end ? std::invoke(std::get(*begin), ev, std::forward(args)...) : std::invoke(std::get(*std::prev(disp.cend())), ev, std::forward(args)...); } @@ -219,8 +217,8 @@ requires (std::invocable && I > 0) static constexpr void dispatch(T ev, const std::array, I>& disp, C *obj, Args&&... args) noexcept { - const auto result { std::equal_range(disp.cbegin(), std::prev(disp.cend()), std::make_tuple(ev, Fn()), tuple_comp) }; - return result.first != result.second ? std::invoke(std::get(*result.first), obj, ev, std::forward(args)...) + const auto [begin,end] { std::equal_range(disp.cbegin(), std::prev(disp.cend()), std::make_tuple(ev, Fn()), tuple_comp) }; + return begin != end ? std::invoke(std::get(*begin), obj, ev, std::forward(args)...) : std::invoke(std::get(*std::prev(disp.cend())), obj, ev, std::forward(args)...); } From 9c38a9439744f0b7e79a8251a87483cfe32d7731 Mon Sep 17 00:00:00 2001 From: David Dight Date: Tue, 13 Aug 2024 10:58:46 +1000 Subject: [PATCH 062/235] pre-rel 1.0.2d --- examples/cbenchmark.cpp | 3 +- include/fix8/conjure_enum.hpp | 83 ++++++++++++++++------------------- 2 files changed, 40 insertions(+), 46 deletions(-) diff --git a/examples/cbenchmark.cpp b/examples/cbenchmark.cpp index e432102..6325242 100644 --- a/examples/cbenchmark.cpp +++ b/examples/cbenchmark.cpp @@ -33,12 +33,11 @@ // cl /nologo /MD /std:c++latest /Bt+ /I ..\include ..\examples\cbenchmark.cpp|find "c1xx.dll" //---------------------------------------------------------------------------------------- #include -#define FIX8_CONJURE_ENUM_MINIMAL +#define FIX8_CONJURE_ENUM_ALL_OPTIMIZATIONS #include //----------------------------------------------------------------------------------------- FIX8_CONJURE_ENUM_SET_RANGE_INTS(std::errc, 0, 71) -FIX8_CONJURE_ENUM_SET_FLAGS(std::errc,true,true) int test_conjure_enum(std::errc err) { diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 46b2ff9..6fd8106 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -41,6 +41,19 @@ #endif //---------------------------------------------------------------------------------------- +#if defined FIX8_CONJURE_ENUM_ALL_OPTIMIZATIONS +# if not defined FIX8_CONJURE_ENUM_IS_CONTINUOUS +# define FIX8_CONJURE_ENUM_IS_CONTINUOUS +# endif +# if not defined FIX8_CONJURE_ENUM_NO_ANON +# define FIX8_CONJURE_ENUM_NO_ANON +# endif +# if not defined FIX8_CONJURE_ENUM_MINIMAL +# define FIX8_CONJURE_ENUM_MINIMAL +# endif +#endif + +//----------------------------------------------------------------------------------------- #include #include #include @@ -170,21 +183,6 @@ struct enum_range final : public static_only #define FIX8_CONJURE_ENUM_SET_RANGE(minv,maxv) \ FIX8_CONJURE_ENUM_SET_RANGE_INTS(decltype(minv),static_cast(minv), static_cast(maxv)) -//----------------------------------------------------------------------------------------- -// You can specialise this class to define custom flags for your enum -//----------------------------------------------------------------------------------------- -template -struct enum_flags final : public static_only -{ - static constexpr bool is_continuous{}, no_anon{}; -}; - -//----------------------------------------------------------------------------------------- -// Convenience macros for above -//----------------------------------------------------------------------------------------- -#define FIX8_CONJURE_ENUM_SET_FLAGS(ec,iscont,noanon) \ - template<> struct FIX8::enum_flags { static constexpr int is_continuous{iscont}, no_anon{noanon}; }; - //----------------------------------------------------------------------------------------- template class conjure_enum final : public static_only @@ -216,9 +214,10 @@ class conjure_enum final : public static_only { if constexpr (_epeek_v[ep + cs::get_spec().size() + 1] == '(') return false; - if constexpr (!enum_flags::no_anon) - if constexpr (_epeek_v.find(cs::get_spec(), ep + cs::get_spec().size()) != std::string_view::npos) // is anon - return true; +#if not defined FIX8_CONJURE_ENUM_NO_ANON + if constexpr (_epeek_v.find(cs::get_spec(), ep + cs::get_spec().size()) != std::string_view::npos) // is anon + return true; +#endif } else if constexpr (_epeek_v.find_first_of(cs::get_spec(), ep + cs::get_spec().size()) != std::string_view::npos) return true; @@ -235,22 +234,19 @@ class conjure_enum final : public static_only template static constexpr auto _values(std::index_sequence) noexcept { - if constexpr (enum_flags::is_continuous) - { - static_assert(sizeof...(I) > 0, "conjure_enum requires non-empty enum"); - return std::array{static_cast(enum_min_value + I)... }; - } - else - { - constexpr std::array valid { _is_valid(enum_min_value + I)>()... }; - constexpr auto valid_cnt { std::count_if(valid.cbegin(), valid.cend(), [](bool val) noexcept { return val; }) }; - static_assert(valid_cnt > 0, "conjure_enum requires non-empty enum"); - std::array vals{}; - for(std::size_t idx{}, nn{}; nn < valid_cnt; ++idx) - if (valid[idx]) - vals[nn++] = static_cast(enum_min_value + idx); - return vals; - } +#if defined FIX8_CONJURE_ENUM_IS_CONTINUOUS + static_assert(sizeof...(I) > 0, "conjure_enum requires non-empty enum"); + return std::array{static_cast(enum_min_value + I)... }; +#else + constexpr std::array valid { _is_valid(enum_min_value + I)>()... }; + constexpr auto valid_cnt { std::count_if(valid.cbegin(), valid.cend(), [](bool val) noexcept { return val; }) }; + static_assert(valid_cnt > 0, "conjure_enum requires non-empty enum"); + std::array vals{}; + for(std::size_t idx{}, nn{}; nn < valid_cnt; ++idx) + if (valid[idx]) + vals[nn++] = static_cast(enum_min_value + idx); + return vals; +#endif } template @@ -259,20 +255,19 @@ class conjure_enum final : public static_only constexpr auto ep { _epeek_v.rfind(cs::get_spec()) }; if constexpr (ep == std::string_view::npos) return {}; - if constexpr (!enum_flags::no_anon) +#if not defined FIX8_CONJURE_ENUM_NO_ANON + if constexpr (_epeek_v[ep + cs::get_spec().size()] == cs::get_spec()) { - if constexpr (_epeek_v[ep + cs::get_spec().size()] == cs::get_spec()) - { #if defined __clang__ - if constexpr (_epeek_v[ep + cs::get_spec().size() + 1] == cs::get_spec()) - return {}; + if constexpr (_epeek_v[ep + cs::get_spec().size() + 1] == cs::get_spec()) + return {}; #endif - if (constexpr auto lstr { _epeek_v.substr(ep + cs::get_spec().size()) }; - lstr.find(cs::get_spec()) != std::string_view::npos) // is anon - if constexpr (constexpr auto lc { lstr.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) - return lstr.substr(cs::get_spec().size() + 2, lc - (cs::get_spec().size() + 2)); // eat "::" - } + if (constexpr auto lstr { _epeek_v.substr(ep + cs::get_spec().size()) }; + lstr.find(cs::get_spec()) != std::string_view::npos) // is anon + if constexpr (constexpr auto lc { lstr.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) + return lstr.substr(cs::get_spec().size() + 2, lc - (cs::get_spec().size() + 2)); // eat "::" } +#endif constexpr std::string_view result { _epeek_v.substr(ep + cs::get_spec().size()) }; if constexpr (constexpr auto lc { result.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) return result.substr(0, lc); From e663c8a1e01d86c2632009f1748822347c005b37 Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 14 Aug 2024 05:24:13 +1000 Subject: [PATCH 063/235] pre-rel 1.0.2d --- examples/cbenchmark.cpp | 3 +- include/fix8/conjure_enum.hpp | 83 +++++++++++++++++++---------------- 2 files changed, 46 insertions(+), 40 deletions(-) diff --git a/examples/cbenchmark.cpp b/examples/cbenchmark.cpp index 6325242..e432102 100644 --- a/examples/cbenchmark.cpp +++ b/examples/cbenchmark.cpp @@ -33,11 +33,12 @@ // cl /nologo /MD /std:c++latest /Bt+ /I ..\include ..\examples\cbenchmark.cpp|find "c1xx.dll" //---------------------------------------------------------------------------------------- #include -#define FIX8_CONJURE_ENUM_ALL_OPTIMIZATIONS +#define FIX8_CONJURE_ENUM_MINIMAL #include //----------------------------------------------------------------------------------------- FIX8_CONJURE_ENUM_SET_RANGE_INTS(std::errc, 0, 71) +FIX8_CONJURE_ENUM_SET_FLAGS(std::errc,true,true) int test_conjure_enum(std::errc err) { diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 6fd8106..46b2ff9 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -41,19 +41,6 @@ #endif //---------------------------------------------------------------------------------------- -#if defined FIX8_CONJURE_ENUM_ALL_OPTIMIZATIONS -# if not defined FIX8_CONJURE_ENUM_IS_CONTINUOUS -# define FIX8_CONJURE_ENUM_IS_CONTINUOUS -# endif -# if not defined FIX8_CONJURE_ENUM_NO_ANON -# define FIX8_CONJURE_ENUM_NO_ANON -# endif -# if not defined FIX8_CONJURE_ENUM_MINIMAL -# define FIX8_CONJURE_ENUM_MINIMAL -# endif -#endif - -//----------------------------------------------------------------------------------------- #include #include #include @@ -183,6 +170,21 @@ struct enum_range final : public static_only #define FIX8_CONJURE_ENUM_SET_RANGE(minv,maxv) \ FIX8_CONJURE_ENUM_SET_RANGE_INTS(decltype(minv),static_cast(minv), static_cast(maxv)) +//----------------------------------------------------------------------------------------- +// You can specialise this class to define custom flags for your enum +//----------------------------------------------------------------------------------------- +template +struct enum_flags final : public static_only +{ + static constexpr bool is_continuous{}, no_anon{}; +}; + +//----------------------------------------------------------------------------------------- +// Convenience macros for above +//----------------------------------------------------------------------------------------- +#define FIX8_CONJURE_ENUM_SET_FLAGS(ec,iscont,noanon) \ + template<> struct FIX8::enum_flags { static constexpr int is_continuous{iscont}, no_anon{noanon}; }; + //----------------------------------------------------------------------------------------- template class conjure_enum final : public static_only @@ -214,10 +216,9 @@ class conjure_enum final : public static_only { if constexpr (_epeek_v[ep + cs::get_spec().size() + 1] == '(') return false; -#if not defined FIX8_CONJURE_ENUM_NO_ANON - if constexpr (_epeek_v.find(cs::get_spec(), ep + cs::get_spec().size()) != std::string_view::npos) // is anon - return true; -#endif + if constexpr (!enum_flags::no_anon) + if constexpr (_epeek_v.find(cs::get_spec(), ep + cs::get_spec().size()) != std::string_view::npos) // is anon + return true; } else if constexpr (_epeek_v.find_first_of(cs::get_spec(), ep + cs::get_spec().size()) != std::string_view::npos) return true; @@ -234,19 +235,22 @@ class conjure_enum final : public static_only template static constexpr auto _values(std::index_sequence) noexcept { -#if defined FIX8_CONJURE_ENUM_IS_CONTINUOUS - static_assert(sizeof...(I) > 0, "conjure_enum requires non-empty enum"); - return std::array{static_cast(enum_min_value + I)... }; -#else - constexpr std::array valid { _is_valid(enum_min_value + I)>()... }; - constexpr auto valid_cnt { std::count_if(valid.cbegin(), valid.cend(), [](bool val) noexcept { return val; }) }; - static_assert(valid_cnt > 0, "conjure_enum requires non-empty enum"); - std::array vals{}; - for(std::size_t idx{}, nn{}; nn < valid_cnt; ++idx) - if (valid[idx]) - vals[nn++] = static_cast(enum_min_value + idx); - return vals; -#endif + if constexpr (enum_flags::is_continuous) + { + static_assert(sizeof...(I) > 0, "conjure_enum requires non-empty enum"); + return std::array{static_cast(enum_min_value + I)... }; + } + else + { + constexpr std::array valid { _is_valid(enum_min_value + I)>()... }; + constexpr auto valid_cnt { std::count_if(valid.cbegin(), valid.cend(), [](bool val) noexcept { return val; }) }; + static_assert(valid_cnt > 0, "conjure_enum requires non-empty enum"); + std::array vals{}; + for(std::size_t idx{}, nn{}; nn < valid_cnt; ++idx) + if (valid[idx]) + vals[nn++] = static_cast(enum_min_value + idx); + return vals; + } } template @@ -255,19 +259,20 @@ class conjure_enum final : public static_only constexpr auto ep { _epeek_v.rfind(cs::get_spec()) }; if constexpr (ep == std::string_view::npos) return {}; -#if not defined FIX8_CONJURE_ENUM_NO_ANON - if constexpr (_epeek_v[ep + cs::get_spec().size()] == cs::get_spec()) + if constexpr (!enum_flags::no_anon) { + if constexpr (_epeek_v[ep + cs::get_spec().size()] == cs::get_spec()) + { #if defined __clang__ - if constexpr (_epeek_v[ep + cs::get_spec().size() + 1] == cs::get_spec()) - return {}; + if constexpr (_epeek_v[ep + cs::get_spec().size() + 1] == cs::get_spec()) + return {}; #endif - if (constexpr auto lstr { _epeek_v.substr(ep + cs::get_spec().size()) }; - lstr.find(cs::get_spec()) != std::string_view::npos) // is anon - if constexpr (constexpr auto lc { lstr.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) - return lstr.substr(cs::get_spec().size() + 2, lc - (cs::get_spec().size() + 2)); // eat "::" + if (constexpr auto lstr { _epeek_v.substr(ep + cs::get_spec().size()) }; + lstr.find(cs::get_spec()) != std::string_view::npos) // is anon + if constexpr (constexpr auto lc { lstr.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) + return lstr.substr(cs::get_spec().size() + 2, lc - (cs::get_spec().size() + 2)); // eat "::" + } } -#endif constexpr std::string_view result { _epeek_v.substr(ep + cs::get_spec().size()) }; if constexpr (constexpr auto lc { result.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) return result.substr(0, lc); From cd5779c6f15bc0caee752f6ee436f8e4bf996398 Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 14 Aug 2024 05:36:40 +1000 Subject: [PATCH 064/235] pre-rel 1.0.2d --- include/fix8/conjure_enum.hpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 46b2ff9..42c2ee9 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -55,8 +55,6 @@ //----------------------------------------------------------------------------------------- namespace FIX8 { -using namespace std::literals::string_view_literals; - //----------------------------------------------------------------------------------------- // global default enum range //----------------------------------------------------------------------------------------- @@ -111,13 +109,13 @@ class cs final : public static_only std::to_array> ({ #if defined __clang__ - { "e = "sv, ']', "(anonymous namespace)"sv, '(' }, { "T = "sv, ']', "(anonymous namespace)"sv, '(' }, + { "e = ", ']', "(anonymous namespace)", '(' }, { "T = ", ']', "(anonymous namespace)", '(' }, #elif defined __GNUC__ - { "e = "sv, ';', ""sv, '<' }, { "T = "sv, ']', "{anonymous}"sv, '{' }, + { "e = ", ';', "", '<' }, { "T = ", ']', "{anonymous}", '{' }, #elif defined _MSC_VER - { "epeek<"sv, '>', "`anonymous-namespace'"sv, '`' }, { "::tpeek"sv, '<', "enum `anonymous namespace'::"sv, '\0' }, - { ""sv, '\0', "`anonymous namespace'::"sv, '\0' }, { ""sv, '\0', "enum "sv, '\0' }, { ""sv, '\0', "class "sv, '\0' }, - { ""sv, '\0', "struct "sv, '\0' }, + { "epeek<", '>', "`anonymous-namespace'", '`' }, { "::tpeek", '<', "enum `anonymous namespace'::", '\0' }, + { "", '\0', "`anonymous namespace'::", '\0' }, { "", '\0', "enum ", '\0' }, { "", '\0', "class ", '\0' }, + { "", '\0', "struct ", '\0' }, #else # error "conjure_enum not supported by your compiler" #endif @@ -180,7 +178,7 @@ struct enum_flags final : public static_only }; //----------------------------------------------------------------------------------------- -// Convenience macros for above +// Convenience macro for above //----------------------------------------------------------------------------------------- #define FIX8_CONJURE_ENUM_SET_FLAGS(ec,iscont,noanon) \ template<> struct FIX8::enum_flags { static constexpr int is_continuous{iscont}, no_anon{noanon}; }; From d9014b940f4609f7e48bb19026208adf94d5b856 Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 14 Aug 2024 05:49:58 +1000 Subject: [PATCH 065/235] updated --- README.md | 46 +++++++++++++++++++++------------------------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 4a50de5..5dfb729 100644 --- a/README.md +++ b/README.md @@ -1474,43 +1474,39 @@ enum_to_string //noscope option not available ``` These are marked ![](assets/notminimalred.svg) in the API documentation above. -## c) Continuous enum optimization +## c) Using `enum_flags` ```c++ -#define FIX8_CONJURE_ENUM_IS_CONTINUOUS +template +struct enum_flags final +{ + static constexpr bool is_continuous{}, no_anon{}; +}; ``` -If your enum(s) are continuous (no gaps) you can enable this compiler optimization -by defining `FIX8_CONJURE_ENUM_IS_CONTINUOUS` _before_ you include `conjure_enum.hpp`. -Our testing shows a reduction in overall compile times. All enums using `conjure_enum.hpp` in the current compilation unit must be continuous. +### i. Continuous enum optimization +The `is_continuous` indicates that your enum(s) are continuous (no gaps). In out testing enable this compiler optimization +shows a reduction in overall compile times. -## d) Anonymous enum optimization -```c++ -#define FIX8_CONJURE_ENUM_NO_ANON -``` -If your enum(s) are not within any anonymous namespaces (rarely used for this purpose), you can enable this compiler optimization -by defining `FIX8_CONJURE_ENUM_NO_ANON` _before_ you include `conjure_enum.hpp`. -Our testing shows a reduction in overall compile times. All enums using `conjure_enum.hpp` in the current compilation unit must be continuous. +### ii. Anonymous enum optimization +The `no_anon` indicates that your enum(s) are not within any anonymous namespaces (rarely used for this purpose). In out testing enable this compiler optimization +shows a reduction in overall compile times. + +### iii. `FIX8_CONJURE_ENUM_SET_FLAGS` +For convenience, this macro is provided to make it easier to set custom flags. This macro takes an enum typename followed by two `bool` values indicating +the values of `is_continuous` and `no_anon`. -## e) Enable all optimizations -```c++ -#define FIX8_CONJURE_ENUM_ALL_OPTIMIZATIONS -``` -You can enable all optimizations described above by defining `FIX8_CONJURE_ENUM_ALL_OPTIMIZATIONS` _before_ you include `conjure_enum.hpp`. -This is the equivalent of defining: ```c++ -#define FIX8_CONJURE_ENUM_MINIMAL -#define FIX8_CONJURE_ENUM_IS_CONTINUOUS -#define FIX8_CONJURE_ENUM_NO_ANON +FIX8_CONJURE_ENUM_SET_FLAGS(range_test, true, true) ``` -## f) Class `conjure_enum` is not constructible +## d) Class `conjure_enum` is not constructible All methods in this class are _static_. You cannot instantiate an object of this type. The same goes for `conjure_type`. -## g) It's not _real_ reflection +## e) It's not _real_ reflection This library provides a workaround (hack :smirk:) to current limitations of C++. There are proposals out there for future versions of the language that will provide proper reflection. See [Reflection TS](https://en.cppreference.com/w/cpp/experimental/reflect) and [Reflection for C++26](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2996r0.html) for examples of some of these. -## h) Use of `std::string_view` +## f) Use of `std::string_view` All of the generated static strings and generated static tables obtained by `std::source_location` use the library defined `fixed_string`. No string copying is done at runtime, resulting in a single static string in your application. All `conjure_enum` methods that return strings _only_ return `std::string_view`. To demonstrate this, lets look at the supplied test application `statictest`: @@ -1631,7 +1627,7 @@ $ It can be observed that there is only _one_ copy of the scoped enum value string in the executable. -## i) Compilation profiling (Clang) +## g) Compilation profiling (Clang) You can profile the compile time for Clang (other compilers TBA). Firstly install [ClangBuildAnalyzer](https://github.com/aras-p/ClangBuildAnalyzer). Then configure `conjure_enum` with: ```CMake From 703ced2161d3c68bbc6112af34d7a3f31bcf0398 Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 14 Aug 2024 05:52:10 +1000 Subject: [PATCH 066/235] updated --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5dfb729..1263752 100644 --- a/README.md +++ b/README.md @@ -1482,12 +1482,13 @@ struct enum_flags final static constexpr bool is_continuous{}, no_anon{}; }; ``` +You can specialise this class to override the defaults and set your own flags on a per enum basis: ### i. Continuous enum optimization -The `is_continuous` indicates that your enum(s) are continuous (no gaps). In out testing enable this compiler optimization +The `is_continuous` flag indicates that your enum(s) are continuous (no gaps). In out testing enabling this compiler optimization shows a reduction in overall compile times. ### ii. Anonymous enum optimization -The `no_anon` indicates that your enum(s) are not within any anonymous namespaces (rarely used for this purpose). In out testing enable this compiler optimization +The `no_anon` indicates flag that your enum(s) are not within any anonymous namespaces (rarely used for this purpose). In out testing enabling this compiler optimization shows a reduction in overall compile times. ### iii. `FIX8_CONJURE_ENUM_SET_FLAGS` From 63efbfb0e13af8aed2e1cef68338ae6af33cf7c9 Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 14 Aug 2024 05:53:43 +1000 Subject: [PATCH 067/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1263752..95cbfe8 100644 --- a/README.md +++ b/README.md @@ -1477,7 +1477,7 @@ These are marked ![](assets/notminimalred.svg) in the API documentation above. ## c) Using `enum_flags` ```c++ template -struct enum_flags final +struct enum_flags { static constexpr bool is_continuous{}, no_anon{}; }; From 66548a0a3cb7f642a0cb90477e45fb3b8a6ac0d8 Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 14 Aug 2024 05:53:50 +1000 Subject: [PATCH 068/235] pre-rel 1.0.2d --- include/fix8/conjure_enum.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 42c2ee9..980d609 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -163,7 +163,7 @@ struct enum_range final : public static_only // Convenience macros for above //----------------------------------------------------------------------------------------- #define FIX8_CONJURE_ENUM_SET_RANGE_INTS(ec,minv,maxv) \ - template<> struct FIX8::enum_range { static constexpr int min{minv}, max{maxv}; }; + template<> struct FIX8::enum_range : public static_only { static constexpr int min{minv}, max{maxv}; }; #define FIX8_CONJURE_ENUM_SET_RANGE(minv,maxv) \ FIX8_CONJURE_ENUM_SET_RANGE_INTS(decltype(minv),static_cast(minv), static_cast(maxv)) @@ -181,7 +181,7 @@ struct enum_flags final : public static_only // Convenience macro for above //----------------------------------------------------------------------------------------- #define FIX8_CONJURE_ENUM_SET_FLAGS(ec,iscont,noanon) \ - template<> struct FIX8::enum_flags { static constexpr int is_continuous{iscont}, no_anon{noanon}; }; + template<> struct FIX8::enum_flags : public static_only { static constexpr int is_continuous{iscont}, no_anon{noanon}; }; //----------------------------------------------------------------------------------------- template From 360ef1df0ea6f3743e1d556556b7a5a13963a813 Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 14 Aug 2024 05:54:32 +1000 Subject: [PATCH 069/235] pre-rel 1.0.2d --- include/fix8/conjure_enum.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 980d609..42c2ee9 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -163,7 +163,7 @@ struct enum_range final : public static_only // Convenience macros for above //----------------------------------------------------------------------------------------- #define FIX8_CONJURE_ENUM_SET_RANGE_INTS(ec,minv,maxv) \ - template<> struct FIX8::enum_range : public static_only { static constexpr int min{minv}, max{maxv}; }; + template<> struct FIX8::enum_range { static constexpr int min{minv}, max{maxv}; }; #define FIX8_CONJURE_ENUM_SET_RANGE(minv,maxv) \ FIX8_CONJURE_ENUM_SET_RANGE_INTS(decltype(minv),static_cast(minv), static_cast(maxv)) @@ -181,7 +181,7 @@ struct enum_flags final : public static_only // Convenience macro for above //----------------------------------------------------------------------------------------- #define FIX8_CONJURE_ENUM_SET_FLAGS(ec,iscont,noanon) \ - template<> struct FIX8::enum_flags : public static_only { static constexpr int is_continuous{iscont}, no_anon{noanon}; }; + template<> struct FIX8::enum_flags { static constexpr int is_continuous{iscont}, no_anon{noanon}; }; //----------------------------------------------------------------------------------------- template From 82c93a2cdae7f4e085a022095f257952c13fc28c Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 14 Aug 2024 06:03:01 +1000 Subject: [PATCH 070/235] updated --- README.md | 47 +++++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 95cbfe8..4a50de5 100644 --- a/README.md +++ b/README.md @@ -1474,40 +1474,43 @@ enum_to_string //noscope option not available ``` These are marked ![](assets/notminimalred.svg) in the API documentation above. -## c) Using `enum_flags` +## c) Continuous enum optimization ```c++ -template -struct enum_flags -{ - static constexpr bool is_continuous{}, no_anon{}; -}; +#define FIX8_CONJURE_ENUM_IS_CONTINUOUS ``` -You can specialise this class to override the defaults and set your own flags on a per enum basis: -### i. Continuous enum optimization -The `is_continuous` flag indicates that your enum(s) are continuous (no gaps). In out testing enabling this compiler optimization -shows a reduction in overall compile times. +If your enum(s) are continuous (no gaps) you can enable this compiler optimization +by defining `FIX8_CONJURE_ENUM_IS_CONTINUOUS` _before_ you include `conjure_enum.hpp`. +Our testing shows a reduction in overall compile times. All enums using `conjure_enum.hpp` in the current compilation unit must be continuous. -### ii. Anonymous enum optimization -The `no_anon` indicates flag that your enum(s) are not within any anonymous namespaces (rarely used for this purpose). In out testing enabling this compiler optimization -shows a reduction in overall compile times. - -### iii. `FIX8_CONJURE_ENUM_SET_FLAGS` -For convenience, this macro is provided to make it easier to set custom flags. This macro takes an enum typename followed by two `bool` values indicating -the values of `is_continuous` and `no_anon`. +## d) Anonymous enum optimization +```c++ +#define FIX8_CONJURE_ENUM_NO_ANON +``` +If your enum(s) are not within any anonymous namespaces (rarely used for this purpose), you can enable this compiler optimization +by defining `FIX8_CONJURE_ENUM_NO_ANON` _before_ you include `conjure_enum.hpp`. +Our testing shows a reduction in overall compile times. All enums using `conjure_enum.hpp` in the current compilation unit must be continuous. +## e) Enable all optimizations +```c++ +#define FIX8_CONJURE_ENUM_ALL_OPTIMIZATIONS +``` +You can enable all optimizations described above by defining `FIX8_CONJURE_ENUM_ALL_OPTIMIZATIONS` _before_ you include `conjure_enum.hpp`. +This is the equivalent of defining: ```c++ -FIX8_CONJURE_ENUM_SET_FLAGS(range_test, true, true) +#define FIX8_CONJURE_ENUM_MINIMAL +#define FIX8_CONJURE_ENUM_IS_CONTINUOUS +#define FIX8_CONJURE_ENUM_NO_ANON ``` -## d) Class `conjure_enum` is not constructible +## f) Class `conjure_enum` is not constructible All methods in this class are _static_. You cannot instantiate an object of this type. The same goes for `conjure_type`. -## e) It's not _real_ reflection +## g) It's not _real_ reflection This library provides a workaround (hack :smirk:) to current limitations of C++. There are proposals out there for future versions of the language that will provide proper reflection. See [Reflection TS](https://en.cppreference.com/w/cpp/experimental/reflect) and [Reflection for C++26](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2996r0.html) for examples of some of these. -## f) Use of `std::string_view` +## h) Use of `std::string_view` All of the generated static strings and generated static tables obtained by `std::source_location` use the library defined `fixed_string`. No string copying is done at runtime, resulting in a single static string in your application. All `conjure_enum` methods that return strings _only_ return `std::string_view`. To demonstrate this, lets look at the supplied test application `statictest`: @@ -1628,7 +1631,7 @@ $ It can be observed that there is only _one_ copy of the scoped enum value string in the executable. -## g) Compilation profiling (Clang) +## i) Compilation profiling (Clang) You can profile the compile time for Clang (other compilers TBA). Firstly install [ClangBuildAnalyzer](https://github.com/aras-p/ClangBuildAnalyzer). Then configure `conjure_enum` with: ```CMake From 040dbec73535dab4678626c5de8b245099323587 Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 14 Aug 2024 06:03:06 +1000 Subject: [PATCH 071/235] pre-rel 1.0.2d --- examples/cbenchmark.cpp | 1 - include/fix8/conjure_enum.hpp | 95 +++++++++++++++++------------------ 2 files changed, 46 insertions(+), 50 deletions(-) diff --git a/examples/cbenchmark.cpp b/examples/cbenchmark.cpp index e432102..98259a7 100644 --- a/examples/cbenchmark.cpp +++ b/examples/cbenchmark.cpp @@ -38,7 +38,6 @@ //----------------------------------------------------------------------------------------- FIX8_CONJURE_ENUM_SET_RANGE_INTS(std::errc, 0, 71) -FIX8_CONJURE_ENUM_SET_FLAGS(std::errc,true,true) int test_conjure_enum(std::errc err) { diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 42c2ee9..6fd8106 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -41,6 +41,19 @@ #endif //---------------------------------------------------------------------------------------- +#if defined FIX8_CONJURE_ENUM_ALL_OPTIMIZATIONS +# if not defined FIX8_CONJURE_ENUM_IS_CONTINUOUS +# define FIX8_CONJURE_ENUM_IS_CONTINUOUS +# endif +# if not defined FIX8_CONJURE_ENUM_NO_ANON +# define FIX8_CONJURE_ENUM_NO_ANON +# endif +# if not defined FIX8_CONJURE_ENUM_MINIMAL +# define FIX8_CONJURE_ENUM_MINIMAL +# endif +#endif + +//----------------------------------------------------------------------------------------- #include #include #include @@ -55,6 +68,8 @@ //----------------------------------------------------------------------------------------- namespace FIX8 { +using namespace std::literals::string_view_literals; + //----------------------------------------------------------------------------------------- // global default enum range //----------------------------------------------------------------------------------------- @@ -109,13 +124,13 @@ class cs final : public static_only std::to_array> ({ #if defined __clang__ - { "e = ", ']', "(anonymous namespace)", '(' }, { "T = ", ']', "(anonymous namespace)", '(' }, + { "e = "sv, ']', "(anonymous namespace)"sv, '(' }, { "T = "sv, ']', "(anonymous namespace)"sv, '(' }, #elif defined __GNUC__ - { "e = ", ';', "", '<' }, { "T = ", ']', "{anonymous}", '{' }, + { "e = "sv, ';', ""sv, '<' }, { "T = "sv, ']', "{anonymous}"sv, '{' }, #elif defined _MSC_VER - { "epeek<", '>', "`anonymous-namespace'", '`' }, { "::tpeek", '<', "enum `anonymous namespace'::", '\0' }, - { "", '\0', "`anonymous namespace'::", '\0' }, { "", '\0', "enum ", '\0' }, { "", '\0', "class ", '\0' }, - { "", '\0', "struct ", '\0' }, + { "epeek<"sv, '>', "`anonymous-namespace'"sv, '`' }, { "::tpeek"sv, '<', "enum `anonymous namespace'::"sv, '\0' }, + { ""sv, '\0', "`anonymous namespace'::"sv, '\0' }, { ""sv, '\0', "enum "sv, '\0' }, { ""sv, '\0', "class "sv, '\0' }, + { ""sv, '\0', "struct "sv, '\0' }, #else # error "conjure_enum not supported by your compiler" #endif @@ -168,21 +183,6 @@ struct enum_range final : public static_only #define FIX8_CONJURE_ENUM_SET_RANGE(minv,maxv) \ FIX8_CONJURE_ENUM_SET_RANGE_INTS(decltype(minv),static_cast(minv), static_cast(maxv)) -//----------------------------------------------------------------------------------------- -// You can specialise this class to define custom flags for your enum -//----------------------------------------------------------------------------------------- -template -struct enum_flags final : public static_only -{ - static constexpr bool is_continuous{}, no_anon{}; -}; - -//----------------------------------------------------------------------------------------- -// Convenience macro for above -//----------------------------------------------------------------------------------------- -#define FIX8_CONJURE_ENUM_SET_FLAGS(ec,iscont,noanon) \ - template<> struct FIX8::enum_flags { static constexpr int is_continuous{iscont}, no_anon{noanon}; }; - //----------------------------------------------------------------------------------------- template class conjure_enum final : public static_only @@ -214,9 +214,10 @@ class conjure_enum final : public static_only { if constexpr (_epeek_v[ep + cs::get_spec().size() + 1] == '(') return false; - if constexpr (!enum_flags::no_anon) - if constexpr (_epeek_v.find(cs::get_spec(), ep + cs::get_spec().size()) != std::string_view::npos) // is anon - return true; +#if not defined FIX8_CONJURE_ENUM_NO_ANON + if constexpr (_epeek_v.find(cs::get_spec(), ep + cs::get_spec().size()) != std::string_view::npos) // is anon + return true; +#endif } else if constexpr (_epeek_v.find_first_of(cs::get_spec(), ep + cs::get_spec().size()) != std::string_view::npos) return true; @@ -233,22 +234,19 @@ class conjure_enum final : public static_only template static constexpr auto _values(std::index_sequence) noexcept { - if constexpr (enum_flags::is_continuous) - { - static_assert(sizeof...(I) > 0, "conjure_enum requires non-empty enum"); - return std::array{static_cast(enum_min_value + I)... }; - } - else - { - constexpr std::array valid { _is_valid(enum_min_value + I)>()... }; - constexpr auto valid_cnt { std::count_if(valid.cbegin(), valid.cend(), [](bool val) noexcept { return val; }) }; - static_assert(valid_cnt > 0, "conjure_enum requires non-empty enum"); - std::array vals{}; - for(std::size_t idx{}, nn{}; nn < valid_cnt; ++idx) - if (valid[idx]) - vals[nn++] = static_cast(enum_min_value + idx); - return vals; - } +#if defined FIX8_CONJURE_ENUM_IS_CONTINUOUS + static_assert(sizeof...(I) > 0, "conjure_enum requires non-empty enum"); + return std::array{static_cast(enum_min_value + I)... }; +#else + constexpr std::array valid { _is_valid(enum_min_value + I)>()... }; + constexpr auto valid_cnt { std::count_if(valid.cbegin(), valid.cend(), [](bool val) noexcept { return val; }) }; + static_assert(valid_cnt > 0, "conjure_enum requires non-empty enum"); + std::array vals{}; + for(std::size_t idx{}, nn{}; nn < valid_cnt; ++idx) + if (valid[idx]) + vals[nn++] = static_cast(enum_min_value + idx); + return vals; +#endif } template @@ -257,20 +255,19 @@ class conjure_enum final : public static_only constexpr auto ep { _epeek_v.rfind(cs::get_spec()) }; if constexpr (ep == std::string_view::npos) return {}; - if constexpr (!enum_flags::no_anon) +#if not defined FIX8_CONJURE_ENUM_NO_ANON + if constexpr (_epeek_v[ep + cs::get_spec().size()] == cs::get_spec()) { - if constexpr (_epeek_v[ep + cs::get_spec().size()] == cs::get_spec()) - { #if defined __clang__ - if constexpr (_epeek_v[ep + cs::get_spec().size() + 1] == cs::get_spec()) - return {}; + if constexpr (_epeek_v[ep + cs::get_spec().size() + 1] == cs::get_spec()) + return {}; #endif - if (constexpr auto lstr { _epeek_v.substr(ep + cs::get_spec().size()) }; - lstr.find(cs::get_spec()) != std::string_view::npos) // is anon - if constexpr (constexpr auto lc { lstr.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) - return lstr.substr(cs::get_spec().size() + 2, lc - (cs::get_spec().size() + 2)); // eat "::" - } + if (constexpr auto lstr { _epeek_v.substr(ep + cs::get_spec().size()) }; + lstr.find(cs::get_spec()) != std::string_view::npos) // is anon + if constexpr (constexpr auto lc { lstr.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) + return lstr.substr(cs::get_spec().size() + 2, lc - (cs::get_spec().size() + 2)); // eat "::" } +#endif constexpr std::string_view result { _epeek_v.substr(ep + cs::get_spec().size()) }; if constexpr (constexpr auto lc { result.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) return result.substr(0, lc); From adeb35aac7a3fe391514797ba7b516360aea7324 Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 14 Aug 2024 06:04:08 +1000 Subject: [PATCH 072/235] pre-rel 1.0.2d --- examples/cbenchmark.cpp | 1 + include/fix8/conjure_enum.hpp | 97 ++++++++++++++++++----------------- 2 files changed, 51 insertions(+), 47 deletions(-) diff --git a/examples/cbenchmark.cpp b/examples/cbenchmark.cpp index 98259a7..e432102 100644 --- a/examples/cbenchmark.cpp +++ b/examples/cbenchmark.cpp @@ -38,6 +38,7 @@ //----------------------------------------------------------------------------------------- FIX8_CONJURE_ENUM_SET_RANGE_INTS(std::errc, 0, 71) +FIX8_CONJURE_ENUM_SET_FLAGS(std::errc,true,true) int test_conjure_enum(std::errc err) { diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 6fd8106..980d609 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -41,19 +41,6 @@ #endif //---------------------------------------------------------------------------------------- -#if defined FIX8_CONJURE_ENUM_ALL_OPTIMIZATIONS -# if not defined FIX8_CONJURE_ENUM_IS_CONTINUOUS -# define FIX8_CONJURE_ENUM_IS_CONTINUOUS -# endif -# if not defined FIX8_CONJURE_ENUM_NO_ANON -# define FIX8_CONJURE_ENUM_NO_ANON -# endif -# if not defined FIX8_CONJURE_ENUM_MINIMAL -# define FIX8_CONJURE_ENUM_MINIMAL -# endif -#endif - -//----------------------------------------------------------------------------------------- #include #include #include @@ -68,8 +55,6 @@ //----------------------------------------------------------------------------------------- namespace FIX8 { -using namespace std::literals::string_view_literals; - //----------------------------------------------------------------------------------------- // global default enum range //----------------------------------------------------------------------------------------- @@ -124,13 +109,13 @@ class cs final : public static_only std::to_array> ({ #if defined __clang__ - { "e = "sv, ']', "(anonymous namespace)"sv, '(' }, { "T = "sv, ']', "(anonymous namespace)"sv, '(' }, + { "e = ", ']', "(anonymous namespace)", '(' }, { "T = ", ']', "(anonymous namespace)", '(' }, #elif defined __GNUC__ - { "e = "sv, ';', ""sv, '<' }, { "T = "sv, ']', "{anonymous}"sv, '{' }, + { "e = ", ';', "", '<' }, { "T = ", ']', "{anonymous}", '{' }, #elif defined _MSC_VER - { "epeek<"sv, '>', "`anonymous-namespace'"sv, '`' }, { "::tpeek"sv, '<', "enum `anonymous namespace'::"sv, '\0' }, - { ""sv, '\0', "`anonymous namespace'::"sv, '\0' }, { ""sv, '\0', "enum "sv, '\0' }, { ""sv, '\0', "class "sv, '\0' }, - { ""sv, '\0', "struct "sv, '\0' }, + { "epeek<", '>', "`anonymous-namespace'", '`' }, { "::tpeek", '<', "enum `anonymous namespace'::", '\0' }, + { "", '\0', "`anonymous namespace'::", '\0' }, { "", '\0', "enum ", '\0' }, { "", '\0', "class ", '\0' }, + { "", '\0', "struct ", '\0' }, #else # error "conjure_enum not supported by your compiler" #endif @@ -178,11 +163,26 @@ struct enum_range final : public static_only // Convenience macros for above //----------------------------------------------------------------------------------------- #define FIX8_CONJURE_ENUM_SET_RANGE_INTS(ec,minv,maxv) \ - template<> struct FIX8::enum_range { static constexpr int min{minv}, max{maxv}; }; + template<> struct FIX8::enum_range : public static_only { static constexpr int min{minv}, max{maxv}; }; #define FIX8_CONJURE_ENUM_SET_RANGE(minv,maxv) \ FIX8_CONJURE_ENUM_SET_RANGE_INTS(decltype(minv),static_cast(minv), static_cast(maxv)) +//----------------------------------------------------------------------------------------- +// You can specialise this class to define custom flags for your enum +//----------------------------------------------------------------------------------------- +template +struct enum_flags final : public static_only +{ + static constexpr bool is_continuous{}, no_anon{}; +}; + +//----------------------------------------------------------------------------------------- +// Convenience macro for above +//----------------------------------------------------------------------------------------- +#define FIX8_CONJURE_ENUM_SET_FLAGS(ec,iscont,noanon) \ + template<> struct FIX8::enum_flags : public static_only { static constexpr int is_continuous{iscont}, no_anon{noanon}; }; + //----------------------------------------------------------------------------------------- template class conjure_enum final : public static_only @@ -214,10 +214,9 @@ class conjure_enum final : public static_only { if constexpr (_epeek_v[ep + cs::get_spec().size() + 1] == '(') return false; -#if not defined FIX8_CONJURE_ENUM_NO_ANON - if constexpr (_epeek_v.find(cs::get_spec(), ep + cs::get_spec().size()) != std::string_view::npos) // is anon - return true; -#endif + if constexpr (!enum_flags::no_anon) + if constexpr (_epeek_v.find(cs::get_spec(), ep + cs::get_spec().size()) != std::string_view::npos) // is anon + return true; } else if constexpr (_epeek_v.find_first_of(cs::get_spec(), ep + cs::get_spec().size()) != std::string_view::npos) return true; @@ -234,19 +233,22 @@ class conjure_enum final : public static_only template static constexpr auto _values(std::index_sequence) noexcept { -#if defined FIX8_CONJURE_ENUM_IS_CONTINUOUS - static_assert(sizeof...(I) > 0, "conjure_enum requires non-empty enum"); - return std::array{static_cast(enum_min_value + I)... }; -#else - constexpr std::array valid { _is_valid(enum_min_value + I)>()... }; - constexpr auto valid_cnt { std::count_if(valid.cbegin(), valid.cend(), [](bool val) noexcept { return val; }) }; - static_assert(valid_cnt > 0, "conjure_enum requires non-empty enum"); - std::array vals{}; - for(std::size_t idx{}, nn{}; nn < valid_cnt; ++idx) - if (valid[idx]) - vals[nn++] = static_cast(enum_min_value + idx); - return vals; -#endif + if constexpr (enum_flags::is_continuous) + { + static_assert(sizeof...(I) > 0, "conjure_enum requires non-empty enum"); + return std::array{static_cast(enum_min_value + I)... }; + } + else + { + constexpr std::array valid { _is_valid(enum_min_value + I)>()... }; + constexpr auto valid_cnt { std::count_if(valid.cbegin(), valid.cend(), [](bool val) noexcept { return val; }) }; + static_assert(valid_cnt > 0, "conjure_enum requires non-empty enum"); + std::array vals{}; + for(std::size_t idx{}, nn{}; nn < valid_cnt; ++idx) + if (valid[idx]) + vals[nn++] = static_cast(enum_min_value + idx); + return vals; + } } template @@ -255,19 +257,20 @@ class conjure_enum final : public static_only constexpr auto ep { _epeek_v.rfind(cs::get_spec()) }; if constexpr (ep == std::string_view::npos) return {}; -#if not defined FIX8_CONJURE_ENUM_NO_ANON - if constexpr (_epeek_v[ep + cs::get_spec().size()] == cs::get_spec()) + if constexpr (!enum_flags::no_anon) { + if constexpr (_epeek_v[ep + cs::get_spec().size()] == cs::get_spec()) + { #if defined __clang__ - if constexpr (_epeek_v[ep + cs::get_spec().size() + 1] == cs::get_spec()) - return {}; + if constexpr (_epeek_v[ep + cs::get_spec().size() + 1] == cs::get_spec()) + return {}; #endif - if (constexpr auto lstr { _epeek_v.substr(ep + cs::get_spec().size()) }; - lstr.find(cs::get_spec()) != std::string_view::npos) // is anon - if constexpr (constexpr auto lc { lstr.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) - return lstr.substr(cs::get_spec().size() + 2, lc - (cs::get_spec().size() + 2)); // eat "::" + if (constexpr auto lstr { _epeek_v.substr(ep + cs::get_spec().size()) }; + lstr.find(cs::get_spec()) != std::string_view::npos) // is anon + if constexpr (constexpr auto lc { lstr.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) + return lstr.substr(cs::get_spec().size() + 2, lc - (cs::get_spec().size() + 2)); // eat "::" + } } -#endif constexpr std::string_view result { _epeek_v.substr(ep + cs::get_spec().size()) }; if constexpr (constexpr auto lc { result.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) return result.substr(0, lc); From 75e1f7a2acbc2d6a5333205018a605c0319ba16b Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 14 Aug 2024 06:06:41 +1000 Subject: [PATCH 073/235] pre-rel 1.0.2d --- README.md | 47 ++++++++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 4a50de5..1812bbd 100644 --- a/README.md +++ b/README.md @@ -1474,43 +1474,40 @@ enum_to_string //noscope option not available ``` These are marked ![](assets/notminimalred.svg) in the API documentation above. -## c) Continuous enum optimization +## c) Using `enum_flags` ```c++ -#define FIX8_CONJURE_ENUM_IS_CONTINUOUS +template +struct enum_flags +{ + static constexpr bool is_continuous{}, no_anon{}; +}; ``` -If your enum(s) are continuous (no gaps) you can enable this compiler optimization -by defining `FIX8_CONJURE_ENUM_IS_CONTINUOUS` _before_ you include `conjure_enum.hpp`. -Our testing shows a reduction in overall compile times. All enums using `conjure_enum.hpp` in the current compilation unit must be continuous. +You can specialise this class to override the defaults and set your own flags on a per enum basis: +### i. Continuous enum optimization +The `is_continuous` flag indicates that your enum(s) are continuous (no gaps). In our testing enabling this compiler optimization +shows a reduction in overall compile times. -## d) Anonymous enum optimization -```c++ -#define FIX8_CONJURE_ENUM_NO_ANON -``` -If your enum(s) are not within any anonymous namespaces (rarely used for this purpose), you can enable this compiler optimization -by defining `FIX8_CONJURE_ENUM_NO_ANON` _before_ you include `conjure_enum.hpp`. -Our testing shows a reduction in overall compile times. All enums using `conjure_enum.hpp` in the current compilation unit must be continuous. +### ii. Anonymous enum optimization +The `no_anon` indicates flag that your enum(s) are not within any anonymous namespaces (rarely used for this purpose). In our testing enabling this compiler optimization +shows a reduction in overall compile times. + +### iii. `FIX8_CONJURE_ENUM_SET_FLAGS` +For convenience, this macro is provided to make it easier to set custom flags. This macro takes an enum typename followed by two `bool` values indicating +the values of `is_continuous` and `no_anon`. -## e) Enable all optimizations -```c++ -#define FIX8_CONJURE_ENUM_ALL_OPTIMIZATIONS -``` -You can enable all optimizations described above by defining `FIX8_CONJURE_ENUM_ALL_OPTIMIZATIONS` _before_ you include `conjure_enum.hpp`. -This is the equivalent of defining: ```c++ -#define FIX8_CONJURE_ENUM_MINIMAL -#define FIX8_CONJURE_ENUM_IS_CONTINUOUS -#define FIX8_CONJURE_ENUM_NO_ANON +FIX8_CONJURE_ENUM_SET_FLAGS(range_test, true, true) ``` -## f) Class `conjure_enum` is not constructible +## d) Class `conjure_enum` is not constructible All methods in this class are _static_. You cannot instantiate an object of this type. The same goes for `conjure_type`. -## g) It's not _real_ reflection +## e) It's not _real_ reflection This library provides a workaround (hack :smirk:) to current limitations of C++. There are proposals out there for future versions of the language that will provide proper reflection. See [Reflection TS](https://en.cppreference.com/w/cpp/experimental/reflect) and [Reflection for C++26](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2996r0.html) for examples of some of these. -## h) Use of `std::string_view` +## f) Use of `std::string_view` All of the generated static strings and generated static tables obtained by `std::source_location` use the library defined `fixed_string`. No string copying is done at runtime, resulting in a single static string in your application. All `conjure_enum` methods that return strings _only_ return `std::string_view`. To demonstrate this, lets look at the supplied test application `statictest`: @@ -1631,7 +1628,7 @@ $ It can be observed that there is only _one_ copy of the scoped enum value string in the executable. -## i) Compilation profiling (Clang) +## g) Compilation profiling (Clang) You can profile the compile time for Clang (other compilers TBA). Firstly install [ClangBuildAnalyzer](https://github.com/aras-p/ClangBuildAnalyzer). Then configure `conjure_enum` with: ```CMake From ce3df532ce31417f3d8fe092a724910089289146 Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 14 Aug 2024 06:07:17 +1000 Subject: [PATCH 074/235] pre-rel 1.0.2d --- include/fix8/conjure_enum.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 980d609..0cc2907 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -163,7 +163,7 @@ struct enum_range final : public static_only // Convenience macros for above //----------------------------------------------------------------------------------------- #define FIX8_CONJURE_ENUM_SET_RANGE_INTS(ec,minv,maxv) \ - template<> struct FIX8::enum_range : public static_only { static constexpr int min{minv}, max{maxv}; }; + template<> struct FIX8::enum_range : public FIX8::static_only { static constexpr int min{minv}, max{maxv}; }; #define FIX8_CONJURE_ENUM_SET_RANGE(minv,maxv) \ FIX8_CONJURE_ENUM_SET_RANGE_INTS(decltype(minv),static_cast(minv), static_cast(maxv)) @@ -181,7 +181,7 @@ struct enum_flags final : public static_only // Convenience macro for above //----------------------------------------------------------------------------------------- #define FIX8_CONJURE_ENUM_SET_FLAGS(ec,iscont,noanon) \ - template<> struct FIX8::enum_flags : public static_only { static constexpr int is_continuous{iscont}, no_anon{noanon}; }; + template<> struct FIX8::enum_flags : public FIX8::static_only { static constexpr int is_continuous{iscont}, no_anon{noanon}; }; //----------------------------------------------------------------------------------------- template From 2ec101bc2813eb236a6dc5ddca2a4a3e0612d593 Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 14 Aug 2024 07:50:11 +1000 Subject: [PATCH 075/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1812bbd..83cc01f 100644 --- a/README.md +++ b/README.md @@ -1753,7 +1753,7 @@ Compilation (2 times): | :--- | :--- | :--- | ---: | | [gcc](https://gcc.gnu.org/projects/cxx-status.html) | `11`, `12`, `13`, `14`| `std::format` not complete in `11`, `12` | `<= 10` | | [clang](https://clang.llvm.org/cxx_status.html) | `15`, `16`, `17`, `18`| Catch2 needs `cxx_std_20` in `15` | `<= 14` | -| [msvc](https://learn.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance) | `16`, `17` | Visual Studio 2019,2022, latest `17.10.5`| `<= 16.9`| +| [msvc](https://learn.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance) | `16`, `17` | Visual Studio 2019,2022, latest `17.11.0`| `<= 16.9`| | [xcode](https://developer.apple.com/support/xcode/) | `15` | Apple LLVM 15.0.0, some issues with `constexpr`, workarounds| `<= 14`| # 9. Compiler issues From a42e784933c33b46cf21cc96b85a9f6efc7d45df Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 14 Aug 2024 07:57:38 +1000 Subject: [PATCH 076/235] updated --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 83cc01f..9687b00 100644 --- a/README.md +++ b/README.md @@ -568,8 +568,8 @@ template // specialisa requires (std::invocable && I > 0) static constexpr void dispatch(T ev, const std::array, I>& disp, C *obj, Args&&... args); ``` -With a given enum, search and call user supplied invocable. Use this method where complex event handling is required, allowing you to easily declare predefined invocable actions -for different enum values. +With a given enum, search for and call user supplied invocable. You can use this method where complex event handling is required, +allowing you to easily declare predefined invocable actions for different enum values. Where invocable returns a value, return this value or a user supplied "not found" value. Where invocable is void, call user supplied "not found" invocable. From 2d9b99c845bcedb9cb9e5e3602a497a997bdfd1c Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 14 Aug 2024 12:49:55 +1000 Subject: [PATCH 077/235] pre-rel 1.0.2e --- include/fix8/conjure_enum.hpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 0cc2907..a8b25b0 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -137,7 +137,7 @@ using stype = cs::stype; using sval = cs::sval; #if defined _MSC_VER -#define CHKMSSTR(e, x) \ +#define CHKMSSTR(e,x) \ if constexpr (constexpr auto ep##x { e.find(cs::get_spec()) }; ep##x != std::string_view::npos) \ return e.substr(ep##x + cs::get_spec().size(), e.size() - (ep##x + cs::get_spec().size())) #endif @@ -163,10 +163,11 @@ struct enum_range final : public static_only // Convenience macros for above //----------------------------------------------------------------------------------------- #define FIX8_CONJURE_ENUM_SET_RANGE_INTS(ec,minv,maxv) \ - template<> struct FIX8::enum_range : public FIX8::static_only { static constexpr int min{minv}, max{maxv}; }; + template<> struct FIX8::enum_range final : public FIX8::static_only \ + { static constexpr int min{minv}, max{maxv}; }; #define FIX8_CONJURE_ENUM_SET_RANGE(minv,maxv) \ - FIX8_CONJURE_ENUM_SET_RANGE_INTS(decltype(minv),static_cast(minv), static_cast(maxv)) + FIX8_CONJURE_ENUM_SET_RANGE_INTS(decltype(minv), static_cast(minv), static_cast(maxv)) //----------------------------------------------------------------------------------------- // You can specialise this class to define custom flags for your enum @@ -181,7 +182,8 @@ struct enum_flags final : public static_only // Convenience macro for above //----------------------------------------------------------------------------------------- #define FIX8_CONJURE_ENUM_SET_FLAGS(ec,iscont,noanon) \ - template<> struct FIX8::enum_flags : public FIX8::static_only { static constexpr int is_continuous{iscont}, no_anon{noanon}; }; + template<> struct FIX8::enum_flags final : public FIX8::static_only \ + { static constexpr int is_continuous{iscont}, no_anon{noanon}; }; //----------------------------------------------------------------------------------------- template From 73b29f3ed4146b6330020d75ab761ffffc013b10 Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 14 Aug 2024 13:02:07 +1000 Subject: [PATCH 078/235] pre-rel 1.0.2d --- examples/cbenchmark.cpp | 3 +- include/fix8/conjure_enum.hpp | 103 ++++++++++++++++------------------ 2 files changed, 50 insertions(+), 56 deletions(-) diff --git a/examples/cbenchmark.cpp b/examples/cbenchmark.cpp index e432102..6325242 100644 --- a/examples/cbenchmark.cpp +++ b/examples/cbenchmark.cpp @@ -33,12 +33,11 @@ // cl /nologo /MD /std:c++latest /Bt+ /I ..\include ..\examples\cbenchmark.cpp|find "c1xx.dll" //---------------------------------------------------------------------------------------- #include -#define FIX8_CONJURE_ENUM_MINIMAL +#define FIX8_CONJURE_ENUM_ALL_OPTIMIZATIONS #include //----------------------------------------------------------------------------------------- FIX8_CONJURE_ENUM_SET_RANGE_INTS(std::errc, 0, 71) -FIX8_CONJURE_ENUM_SET_FLAGS(std::errc,true,true) int test_conjure_enum(std::errc err) { diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index a8b25b0..6fd8106 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -41,6 +41,19 @@ #endif //---------------------------------------------------------------------------------------- +#if defined FIX8_CONJURE_ENUM_ALL_OPTIMIZATIONS +# if not defined FIX8_CONJURE_ENUM_IS_CONTINUOUS +# define FIX8_CONJURE_ENUM_IS_CONTINUOUS +# endif +# if not defined FIX8_CONJURE_ENUM_NO_ANON +# define FIX8_CONJURE_ENUM_NO_ANON +# endif +# if not defined FIX8_CONJURE_ENUM_MINIMAL +# define FIX8_CONJURE_ENUM_MINIMAL +# endif +#endif + +//----------------------------------------------------------------------------------------- #include #include #include @@ -55,6 +68,8 @@ //----------------------------------------------------------------------------------------- namespace FIX8 { +using namespace std::literals::string_view_literals; + //----------------------------------------------------------------------------------------- // global default enum range //----------------------------------------------------------------------------------------- @@ -109,13 +124,13 @@ class cs final : public static_only std::to_array> ({ #if defined __clang__ - { "e = ", ']', "(anonymous namespace)", '(' }, { "T = ", ']', "(anonymous namespace)", '(' }, + { "e = "sv, ']', "(anonymous namespace)"sv, '(' }, { "T = "sv, ']', "(anonymous namespace)"sv, '(' }, #elif defined __GNUC__ - { "e = ", ';', "", '<' }, { "T = ", ']', "{anonymous}", '{' }, + { "e = "sv, ';', ""sv, '<' }, { "T = "sv, ']', "{anonymous}"sv, '{' }, #elif defined _MSC_VER - { "epeek<", '>', "`anonymous-namespace'", '`' }, { "::tpeek", '<', "enum `anonymous namespace'::", '\0' }, - { "", '\0', "`anonymous namespace'::", '\0' }, { "", '\0', "enum ", '\0' }, { "", '\0', "class ", '\0' }, - { "", '\0', "struct ", '\0' }, + { "epeek<"sv, '>', "`anonymous-namespace'"sv, '`' }, { "::tpeek"sv, '<', "enum `anonymous namespace'::"sv, '\0' }, + { ""sv, '\0', "`anonymous namespace'::"sv, '\0' }, { ""sv, '\0', "enum "sv, '\0' }, { ""sv, '\0', "class "sv, '\0' }, + { ""sv, '\0', "struct "sv, '\0' }, #else # error "conjure_enum not supported by your compiler" #endif @@ -137,7 +152,7 @@ using stype = cs::stype; using sval = cs::sval; #if defined _MSC_VER -#define CHKMSSTR(e,x) \ +#define CHKMSSTR(e, x) \ if constexpr (constexpr auto ep##x { e.find(cs::get_spec()) }; ep##x != std::string_view::npos) \ return e.substr(ep##x + cs::get_spec().size(), e.size() - (ep##x + cs::get_spec().size())) #endif @@ -163,27 +178,10 @@ struct enum_range final : public static_only // Convenience macros for above //----------------------------------------------------------------------------------------- #define FIX8_CONJURE_ENUM_SET_RANGE_INTS(ec,minv,maxv) \ - template<> struct FIX8::enum_range final : public FIX8::static_only \ - { static constexpr int min{minv}, max{maxv}; }; + template<> struct FIX8::enum_range { static constexpr int min{minv}, max{maxv}; }; #define FIX8_CONJURE_ENUM_SET_RANGE(minv,maxv) \ - FIX8_CONJURE_ENUM_SET_RANGE_INTS(decltype(minv), static_cast(minv), static_cast(maxv)) - -//----------------------------------------------------------------------------------------- -// You can specialise this class to define custom flags for your enum -//----------------------------------------------------------------------------------------- -template -struct enum_flags final : public static_only -{ - static constexpr bool is_continuous{}, no_anon{}; -}; - -//----------------------------------------------------------------------------------------- -// Convenience macro for above -//----------------------------------------------------------------------------------------- -#define FIX8_CONJURE_ENUM_SET_FLAGS(ec,iscont,noanon) \ - template<> struct FIX8::enum_flags final : public FIX8::static_only \ - { static constexpr int is_continuous{iscont}, no_anon{noanon}; }; + FIX8_CONJURE_ENUM_SET_RANGE_INTS(decltype(minv),static_cast(minv), static_cast(maxv)) //----------------------------------------------------------------------------------------- template @@ -216,9 +214,10 @@ class conjure_enum final : public static_only { if constexpr (_epeek_v[ep + cs::get_spec().size() + 1] == '(') return false; - if constexpr (!enum_flags::no_anon) - if constexpr (_epeek_v.find(cs::get_spec(), ep + cs::get_spec().size()) != std::string_view::npos) // is anon - return true; +#if not defined FIX8_CONJURE_ENUM_NO_ANON + if constexpr (_epeek_v.find(cs::get_spec(), ep + cs::get_spec().size()) != std::string_view::npos) // is anon + return true; +#endif } else if constexpr (_epeek_v.find_first_of(cs::get_spec(), ep + cs::get_spec().size()) != std::string_view::npos) return true; @@ -235,22 +234,19 @@ class conjure_enum final : public static_only template static constexpr auto _values(std::index_sequence) noexcept { - if constexpr (enum_flags::is_continuous) - { - static_assert(sizeof...(I) > 0, "conjure_enum requires non-empty enum"); - return std::array{static_cast(enum_min_value + I)... }; - } - else - { - constexpr std::array valid { _is_valid(enum_min_value + I)>()... }; - constexpr auto valid_cnt { std::count_if(valid.cbegin(), valid.cend(), [](bool val) noexcept { return val; }) }; - static_assert(valid_cnt > 0, "conjure_enum requires non-empty enum"); - std::array vals{}; - for(std::size_t idx{}, nn{}; nn < valid_cnt; ++idx) - if (valid[idx]) - vals[nn++] = static_cast(enum_min_value + idx); - return vals; - } +#if defined FIX8_CONJURE_ENUM_IS_CONTINUOUS + static_assert(sizeof...(I) > 0, "conjure_enum requires non-empty enum"); + return std::array{static_cast(enum_min_value + I)... }; +#else + constexpr std::array valid { _is_valid(enum_min_value + I)>()... }; + constexpr auto valid_cnt { std::count_if(valid.cbegin(), valid.cend(), [](bool val) noexcept { return val; }) }; + static_assert(valid_cnt > 0, "conjure_enum requires non-empty enum"); + std::array vals{}; + for(std::size_t idx{}, nn{}; nn < valid_cnt; ++idx) + if (valid[idx]) + vals[nn++] = static_cast(enum_min_value + idx); + return vals; +#endif } template @@ -259,20 +255,19 @@ class conjure_enum final : public static_only constexpr auto ep { _epeek_v.rfind(cs::get_spec()) }; if constexpr (ep == std::string_view::npos) return {}; - if constexpr (!enum_flags::no_anon) +#if not defined FIX8_CONJURE_ENUM_NO_ANON + if constexpr (_epeek_v[ep + cs::get_spec().size()] == cs::get_spec()) { - if constexpr (_epeek_v[ep + cs::get_spec().size()] == cs::get_spec()) - { #if defined __clang__ - if constexpr (_epeek_v[ep + cs::get_spec().size() + 1] == cs::get_spec()) - return {}; + if constexpr (_epeek_v[ep + cs::get_spec().size() + 1] == cs::get_spec()) + return {}; #endif - if (constexpr auto lstr { _epeek_v.substr(ep + cs::get_spec().size()) }; - lstr.find(cs::get_spec()) != std::string_view::npos) // is anon - if constexpr (constexpr auto lc { lstr.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) - return lstr.substr(cs::get_spec().size() + 2, lc - (cs::get_spec().size() + 2)); // eat "::" - } + if (constexpr auto lstr { _epeek_v.substr(ep + cs::get_spec().size()) }; + lstr.find(cs::get_spec()) != std::string_view::npos) // is anon + if constexpr (constexpr auto lc { lstr.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) + return lstr.substr(cs::get_spec().size() + 2, lc - (cs::get_spec().size() + 2)); // eat "::" } +#endif constexpr std::string_view result { _epeek_v.substr(ep + cs::get_spec().size()) }; if constexpr (constexpr auto lc { result.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) return result.substr(0, lc); From c497101137a627694d226640dd27c87ac8666d06 Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 14 Aug 2024 13:02:56 +1000 Subject: [PATCH 079/235] pre-rel 1.0.2e --- examples/cbenchmark.cpp | 3 +- include/fix8/conjure_enum.hpp | 103 ++++++++++++++++++---------------- 2 files changed, 56 insertions(+), 50 deletions(-) diff --git a/examples/cbenchmark.cpp b/examples/cbenchmark.cpp index 6325242..e432102 100644 --- a/examples/cbenchmark.cpp +++ b/examples/cbenchmark.cpp @@ -33,11 +33,12 @@ // cl /nologo /MD /std:c++latest /Bt+ /I ..\include ..\examples\cbenchmark.cpp|find "c1xx.dll" //---------------------------------------------------------------------------------------- #include -#define FIX8_CONJURE_ENUM_ALL_OPTIMIZATIONS +#define FIX8_CONJURE_ENUM_MINIMAL #include //----------------------------------------------------------------------------------------- FIX8_CONJURE_ENUM_SET_RANGE_INTS(std::errc, 0, 71) +FIX8_CONJURE_ENUM_SET_FLAGS(std::errc,true,true) int test_conjure_enum(std::errc err) { diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 6fd8106..a8b25b0 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -41,19 +41,6 @@ #endif //---------------------------------------------------------------------------------------- -#if defined FIX8_CONJURE_ENUM_ALL_OPTIMIZATIONS -# if not defined FIX8_CONJURE_ENUM_IS_CONTINUOUS -# define FIX8_CONJURE_ENUM_IS_CONTINUOUS -# endif -# if not defined FIX8_CONJURE_ENUM_NO_ANON -# define FIX8_CONJURE_ENUM_NO_ANON -# endif -# if not defined FIX8_CONJURE_ENUM_MINIMAL -# define FIX8_CONJURE_ENUM_MINIMAL -# endif -#endif - -//----------------------------------------------------------------------------------------- #include #include #include @@ -68,8 +55,6 @@ //----------------------------------------------------------------------------------------- namespace FIX8 { -using namespace std::literals::string_view_literals; - //----------------------------------------------------------------------------------------- // global default enum range //----------------------------------------------------------------------------------------- @@ -124,13 +109,13 @@ class cs final : public static_only std::to_array> ({ #if defined __clang__ - { "e = "sv, ']', "(anonymous namespace)"sv, '(' }, { "T = "sv, ']', "(anonymous namespace)"sv, '(' }, + { "e = ", ']', "(anonymous namespace)", '(' }, { "T = ", ']', "(anonymous namespace)", '(' }, #elif defined __GNUC__ - { "e = "sv, ';', ""sv, '<' }, { "T = "sv, ']', "{anonymous}"sv, '{' }, + { "e = ", ';', "", '<' }, { "T = ", ']', "{anonymous}", '{' }, #elif defined _MSC_VER - { "epeek<"sv, '>', "`anonymous-namespace'"sv, '`' }, { "::tpeek"sv, '<', "enum `anonymous namespace'::"sv, '\0' }, - { ""sv, '\0', "`anonymous namespace'::"sv, '\0' }, { ""sv, '\0', "enum "sv, '\0' }, { ""sv, '\0', "class "sv, '\0' }, - { ""sv, '\0', "struct "sv, '\0' }, + { "epeek<", '>', "`anonymous-namespace'", '`' }, { "::tpeek", '<', "enum `anonymous namespace'::", '\0' }, + { "", '\0', "`anonymous namespace'::", '\0' }, { "", '\0', "enum ", '\0' }, { "", '\0', "class ", '\0' }, + { "", '\0', "struct ", '\0' }, #else # error "conjure_enum not supported by your compiler" #endif @@ -152,7 +137,7 @@ using stype = cs::stype; using sval = cs::sval; #if defined _MSC_VER -#define CHKMSSTR(e, x) \ +#define CHKMSSTR(e,x) \ if constexpr (constexpr auto ep##x { e.find(cs::get_spec()) }; ep##x != std::string_view::npos) \ return e.substr(ep##x + cs::get_spec().size(), e.size() - (ep##x + cs::get_spec().size())) #endif @@ -178,10 +163,27 @@ struct enum_range final : public static_only // Convenience macros for above //----------------------------------------------------------------------------------------- #define FIX8_CONJURE_ENUM_SET_RANGE_INTS(ec,minv,maxv) \ - template<> struct FIX8::enum_range { static constexpr int min{minv}, max{maxv}; }; + template<> struct FIX8::enum_range final : public FIX8::static_only \ + { static constexpr int min{minv}, max{maxv}; }; #define FIX8_CONJURE_ENUM_SET_RANGE(minv,maxv) \ - FIX8_CONJURE_ENUM_SET_RANGE_INTS(decltype(minv),static_cast(minv), static_cast(maxv)) + FIX8_CONJURE_ENUM_SET_RANGE_INTS(decltype(minv), static_cast(minv), static_cast(maxv)) + +//----------------------------------------------------------------------------------------- +// You can specialise this class to define custom flags for your enum +//----------------------------------------------------------------------------------------- +template +struct enum_flags final : public static_only +{ + static constexpr bool is_continuous{}, no_anon{}; +}; + +//----------------------------------------------------------------------------------------- +// Convenience macro for above +//----------------------------------------------------------------------------------------- +#define FIX8_CONJURE_ENUM_SET_FLAGS(ec,iscont,noanon) \ + template<> struct FIX8::enum_flags final : public FIX8::static_only \ + { static constexpr int is_continuous{iscont}, no_anon{noanon}; }; //----------------------------------------------------------------------------------------- template @@ -214,10 +216,9 @@ class conjure_enum final : public static_only { if constexpr (_epeek_v[ep + cs::get_spec().size() + 1] == '(') return false; -#if not defined FIX8_CONJURE_ENUM_NO_ANON - if constexpr (_epeek_v.find(cs::get_spec(), ep + cs::get_spec().size()) != std::string_view::npos) // is anon - return true; -#endif + if constexpr (!enum_flags::no_anon) + if constexpr (_epeek_v.find(cs::get_spec(), ep + cs::get_spec().size()) != std::string_view::npos) // is anon + return true; } else if constexpr (_epeek_v.find_first_of(cs::get_spec(), ep + cs::get_spec().size()) != std::string_view::npos) return true; @@ -234,19 +235,22 @@ class conjure_enum final : public static_only template static constexpr auto _values(std::index_sequence) noexcept { -#if defined FIX8_CONJURE_ENUM_IS_CONTINUOUS - static_assert(sizeof...(I) > 0, "conjure_enum requires non-empty enum"); - return std::array{static_cast(enum_min_value + I)... }; -#else - constexpr std::array valid { _is_valid(enum_min_value + I)>()... }; - constexpr auto valid_cnt { std::count_if(valid.cbegin(), valid.cend(), [](bool val) noexcept { return val; }) }; - static_assert(valid_cnt > 0, "conjure_enum requires non-empty enum"); - std::array vals{}; - for(std::size_t idx{}, nn{}; nn < valid_cnt; ++idx) - if (valid[idx]) - vals[nn++] = static_cast(enum_min_value + idx); - return vals; -#endif + if constexpr (enum_flags::is_continuous) + { + static_assert(sizeof...(I) > 0, "conjure_enum requires non-empty enum"); + return std::array{static_cast(enum_min_value + I)... }; + } + else + { + constexpr std::array valid { _is_valid(enum_min_value + I)>()... }; + constexpr auto valid_cnt { std::count_if(valid.cbegin(), valid.cend(), [](bool val) noexcept { return val; }) }; + static_assert(valid_cnt > 0, "conjure_enum requires non-empty enum"); + std::array vals{}; + for(std::size_t idx{}, nn{}; nn < valid_cnt; ++idx) + if (valid[idx]) + vals[nn++] = static_cast(enum_min_value + idx); + return vals; + } } template @@ -255,19 +259,20 @@ class conjure_enum final : public static_only constexpr auto ep { _epeek_v.rfind(cs::get_spec()) }; if constexpr (ep == std::string_view::npos) return {}; -#if not defined FIX8_CONJURE_ENUM_NO_ANON - if constexpr (_epeek_v[ep + cs::get_spec().size()] == cs::get_spec()) + if constexpr (!enum_flags::no_anon) { + if constexpr (_epeek_v[ep + cs::get_spec().size()] == cs::get_spec()) + { #if defined __clang__ - if constexpr (_epeek_v[ep + cs::get_spec().size() + 1] == cs::get_spec()) - return {}; + if constexpr (_epeek_v[ep + cs::get_spec().size() + 1] == cs::get_spec()) + return {}; #endif - if (constexpr auto lstr { _epeek_v.substr(ep + cs::get_spec().size()) }; - lstr.find(cs::get_spec()) != std::string_view::npos) // is anon - if constexpr (constexpr auto lc { lstr.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) - return lstr.substr(cs::get_spec().size() + 2, lc - (cs::get_spec().size() + 2)); // eat "::" + if (constexpr auto lstr { _epeek_v.substr(ep + cs::get_spec().size()) }; + lstr.find(cs::get_spec()) != std::string_view::npos) // is anon + if constexpr (constexpr auto lc { lstr.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) + return lstr.substr(cs::get_spec().size() + 2, lc - (cs::get_spec().size() + 2)); // eat "::" + } } -#endif constexpr std::string_view result { _epeek_v.substr(ep + cs::get_spec().size()) }; if constexpr (constexpr auto lc { result.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) return result.substr(0, lc); From 3d7e3d9f5ceabe655e60c360cc4fab6b42fe5a2c Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 14 Aug 2024 13:06:08 +1000 Subject: [PATCH 080/235] updated --- README.md | 53 ++++++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 9687b00..4a50de5 100644 --- a/README.md +++ b/README.md @@ -568,8 +568,8 @@ template // specialisa requires (std::invocable && I > 0) static constexpr void dispatch(T ev, const std::array, I>& disp, C *obj, Args&&... args); ``` -With a given enum, search for and call user supplied invocable. You can use this method where complex event handling is required, -allowing you to easily declare predefined invocable actions for different enum values. +With a given enum, search and call user supplied invocable. Use this method where complex event handling is required, allowing you to easily declare predefined invocable actions +for different enum values. Where invocable returns a value, return this value or a user supplied "not found" value. Where invocable is void, call user supplied "not found" invocable. @@ -1474,40 +1474,43 @@ enum_to_string //noscope option not available ``` These are marked ![](assets/notminimalred.svg) in the API documentation above. -## c) Using `enum_flags` +## c) Continuous enum optimization ```c++ -template -struct enum_flags -{ - static constexpr bool is_continuous{}, no_anon{}; -}; +#define FIX8_CONJURE_ENUM_IS_CONTINUOUS ``` -You can specialise this class to override the defaults and set your own flags on a per enum basis: -### i. Continuous enum optimization -The `is_continuous` flag indicates that your enum(s) are continuous (no gaps). In our testing enabling this compiler optimization -shows a reduction in overall compile times. +If your enum(s) are continuous (no gaps) you can enable this compiler optimization +by defining `FIX8_CONJURE_ENUM_IS_CONTINUOUS` _before_ you include `conjure_enum.hpp`. +Our testing shows a reduction in overall compile times. All enums using `conjure_enum.hpp` in the current compilation unit must be continuous. -### ii. Anonymous enum optimization -The `no_anon` indicates flag that your enum(s) are not within any anonymous namespaces (rarely used for this purpose). In our testing enabling this compiler optimization -shows a reduction in overall compile times. - -### iii. `FIX8_CONJURE_ENUM_SET_FLAGS` -For convenience, this macro is provided to make it easier to set custom flags. This macro takes an enum typename followed by two `bool` values indicating -the values of `is_continuous` and `no_anon`. +## d) Anonymous enum optimization +```c++ +#define FIX8_CONJURE_ENUM_NO_ANON +``` +If your enum(s) are not within any anonymous namespaces (rarely used for this purpose), you can enable this compiler optimization +by defining `FIX8_CONJURE_ENUM_NO_ANON` _before_ you include `conjure_enum.hpp`. +Our testing shows a reduction in overall compile times. All enums using `conjure_enum.hpp` in the current compilation unit must be continuous. +## e) Enable all optimizations +```c++ +#define FIX8_CONJURE_ENUM_ALL_OPTIMIZATIONS +``` +You can enable all optimizations described above by defining `FIX8_CONJURE_ENUM_ALL_OPTIMIZATIONS` _before_ you include `conjure_enum.hpp`. +This is the equivalent of defining: ```c++ -FIX8_CONJURE_ENUM_SET_FLAGS(range_test, true, true) +#define FIX8_CONJURE_ENUM_MINIMAL +#define FIX8_CONJURE_ENUM_IS_CONTINUOUS +#define FIX8_CONJURE_ENUM_NO_ANON ``` -## d) Class `conjure_enum` is not constructible +## f) Class `conjure_enum` is not constructible All methods in this class are _static_. You cannot instantiate an object of this type. The same goes for `conjure_type`. -## e) It's not _real_ reflection +## g) It's not _real_ reflection This library provides a workaround (hack :smirk:) to current limitations of C++. There are proposals out there for future versions of the language that will provide proper reflection. See [Reflection TS](https://en.cppreference.com/w/cpp/experimental/reflect) and [Reflection for C++26](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2996r0.html) for examples of some of these. -## f) Use of `std::string_view` +## h) Use of `std::string_view` All of the generated static strings and generated static tables obtained by `std::source_location` use the library defined `fixed_string`. No string copying is done at runtime, resulting in a single static string in your application. All `conjure_enum` methods that return strings _only_ return `std::string_view`. To demonstrate this, lets look at the supplied test application `statictest`: @@ -1628,7 +1631,7 @@ $ It can be observed that there is only _one_ copy of the scoped enum value string in the executable. -## g) Compilation profiling (Clang) +## i) Compilation profiling (Clang) You can profile the compile time for Clang (other compilers TBA). Firstly install [ClangBuildAnalyzer](https://github.com/aras-p/ClangBuildAnalyzer). Then configure `conjure_enum` with: ```CMake @@ -1753,7 +1756,7 @@ Compilation (2 times): | :--- | :--- | :--- | ---: | | [gcc](https://gcc.gnu.org/projects/cxx-status.html) | `11`, `12`, `13`, `14`| `std::format` not complete in `11`, `12` | `<= 10` | | [clang](https://clang.llvm.org/cxx_status.html) | `15`, `16`, `17`, `18`| Catch2 needs `cxx_std_20` in `15` | `<= 14` | -| [msvc](https://learn.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance) | `16`, `17` | Visual Studio 2019,2022, latest `17.11.0`| `<= 16.9`| +| [msvc](https://learn.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance) | `16`, `17` | Visual Studio 2019,2022, latest `17.10.5`| `<= 16.9`| | [xcode](https://developer.apple.com/support/xcode/) | `15` | Apple LLVM 15.0.0, some issues with `constexpr`, workarounds| `<= 14`| # 9. Compiler issues From cd79f2b1e02791583754e5ac2ad342152f263a3d Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 14 Aug 2024 13:06:14 +1000 Subject: [PATCH 081/235] pre-rel 1.0.2e --- examples/cbenchmark.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/cbenchmark.cpp b/examples/cbenchmark.cpp index e432102..6325242 100644 --- a/examples/cbenchmark.cpp +++ b/examples/cbenchmark.cpp @@ -33,12 +33,11 @@ // cl /nologo /MD /std:c++latest /Bt+ /I ..\include ..\examples\cbenchmark.cpp|find "c1xx.dll" //---------------------------------------------------------------------------------------- #include -#define FIX8_CONJURE_ENUM_MINIMAL +#define FIX8_CONJURE_ENUM_ALL_OPTIMIZATIONS #include //----------------------------------------------------------------------------------------- FIX8_CONJURE_ENUM_SET_RANGE_INTS(std::errc, 0, 71) -FIX8_CONJURE_ENUM_SET_FLAGS(std::errc,true,true) int test_conjure_enum(std::errc err) { From d4fea562a5bd312f2523d35c7a22fa0a9e51a5ea Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 14 Aug 2024 13:08:14 +1000 Subject: [PATCH 082/235] pre-rel 1.0.2e --- include/fix8/conjure_enum.hpp | 103 ++++++++++++++++------------------ 1 file changed, 49 insertions(+), 54 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index a8b25b0..6fd8106 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -41,6 +41,19 @@ #endif //---------------------------------------------------------------------------------------- +#if defined FIX8_CONJURE_ENUM_ALL_OPTIMIZATIONS +# if not defined FIX8_CONJURE_ENUM_IS_CONTINUOUS +# define FIX8_CONJURE_ENUM_IS_CONTINUOUS +# endif +# if not defined FIX8_CONJURE_ENUM_NO_ANON +# define FIX8_CONJURE_ENUM_NO_ANON +# endif +# if not defined FIX8_CONJURE_ENUM_MINIMAL +# define FIX8_CONJURE_ENUM_MINIMAL +# endif +#endif + +//----------------------------------------------------------------------------------------- #include #include #include @@ -55,6 +68,8 @@ //----------------------------------------------------------------------------------------- namespace FIX8 { +using namespace std::literals::string_view_literals; + //----------------------------------------------------------------------------------------- // global default enum range //----------------------------------------------------------------------------------------- @@ -109,13 +124,13 @@ class cs final : public static_only std::to_array> ({ #if defined __clang__ - { "e = ", ']', "(anonymous namespace)", '(' }, { "T = ", ']', "(anonymous namespace)", '(' }, + { "e = "sv, ']', "(anonymous namespace)"sv, '(' }, { "T = "sv, ']', "(anonymous namespace)"sv, '(' }, #elif defined __GNUC__ - { "e = ", ';', "", '<' }, { "T = ", ']', "{anonymous}", '{' }, + { "e = "sv, ';', ""sv, '<' }, { "T = "sv, ']', "{anonymous}"sv, '{' }, #elif defined _MSC_VER - { "epeek<", '>', "`anonymous-namespace'", '`' }, { "::tpeek", '<', "enum `anonymous namespace'::", '\0' }, - { "", '\0', "`anonymous namespace'::", '\0' }, { "", '\0', "enum ", '\0' }, { "", '\0', "class ", '\0' }, - { "", '\0', "struct ", '\0' }, + { "epeek<"sv, '>', "`anonymous-namespace'"sv, '`' }, { "::tpeek"sv, '<', "enum `anonymous namespace'::"sv, '\0' }, + { ""sv, '\0', "`anonymous namespace'::"sv, '\0' }, { ""sv, '\0', "enum "sv, '\0' }, { ""sv, '\0', "class "sv, '\0' }, + { ""sv, '\0', "struct "sv, '\0' }, #else # error "conjure_enum not supported by your compiler" #endif @@ -137,7 +152,7 @@ using stype = cs::stype; using sval = cs::sval; #if defined _MSC_VER -#define CHKMSSTR(e,x) \ +#define CHKMSSTR(e, x) \ if constexpr (constexpr auto ep##x { e.find(cs::get_spec()) }; ep##x != std::string_view::npos) \ return e.substr(ep##x + cs::get_spec().size(), e.size() - (ep##x + cs::get_spec().size())) #endif @@ -163,27 +178,10 @@ struct enum_range final : public static_only // Convenience macros for above //----------------------------------------------------------------------------------------- #define FIX8_CONJURE_ENUM_SET_RANGE_INTS(ec,minv,maxv) \ - template<> struct FIX8::enum_range final : public FIX8::static_only \ - { static constexpr int min{minv}, max{maxv}; }; + template<> struct FIX8::enum_range { static constexpr int min{minv}, max{maxv}; }; #define FIX8_CONJURE_ENUM_SET_RANGE(minv,maxv) \ - FIX8_CONJURE_ENUM_SET_RANGE_INTS(decltype(minv), static_cast(minv), static_cast(maxv)) - -//----------------------------------------------------------------------------------------- -// You can specialise this class to define custom flags for your enum -//----------------------------------------------------------------------------------------- -template -struct enum_flags final : public static_only -{ - static constexpr bool is_continuous{}, no_anon{}; -}; - -//----------------------------------------------------------------------------------------- -// Convenience macro for above -//----------------------------------------------------------------------------------------- -#define FIX8_CONJURE_ENUM_SET_FLAGS(ec,iscont,noanon) \ - template<> struct FIX8::enum_flags final : public FIX8::static_only \ - { static constexpr int is_continuous{iscont}, no_anon{noanon}; }; + FIX8_CONJURE_ENUM_SET_RANGE_INTS(decltype(minv),static_cast(minv), static_cast(maxv)) //----------------------------------------------------------------------------------------- template @@ -216,9 +214,10 @@ class conjure_enum final : public static_only { if constexpr (_epeek_v[ep + cs::get_spec().size() + 1] == '(') return false; - if constexpr (!enum_flags::no_anon) - if constexpr (_epeek_v.find(cs::get_spec(), ep + cs::get_spec().size()) != std::string_view::npos) // is anon - return true; +#if not defined FIX8_CONJURE_ENUM_NO_ANON + if constexpr (_epeek_v.find(cs::get_spec(), ep + cs::get_spec().size()) != std::string_view::npos) // is anon + return true; +#endif } else if constexpr (_epeek_v.find_first_of(cs::get_spec(), ep + cs::get_spec().size()) != std::string_view::npos) return true; @@ -235,22 +234,19 @@ class conjure_enum final : public static_only template static constexpr auto _values(std::index_sequence) noexcept { - if constexpr (enum_flags::is_continuous) - { - static_assert(sizeof...(I) > 0, "conjure_enum requires non-empty enum"); - return std::array{static_cast(enum_min_value + I)... }; - } - else - { - constexpr std::array valid { _is_valid(enum_min_value + I)>()... }; - constexpr auto valid_cnt { std::count_if(valid.cbegin(), valid.cend(), [](bool val) noexcept { return val; }) }; - static_assert(valid_cnt > 0, "conjure_enum requires non-empty enum"); - std::array vals{}; - for(std::size_t idx{}, nn{}; nn < valid_cnt; ++idx) - if (valid[idx]) - vals[nn++] = static_cast(enum_min_value + idx); - return vals; - } +#if defined FIX8_CONJURE_ENUM_IS_CONTINUOUS + static_assert(sizeof...(I) > 0, "conjure_enum requires non-empty enum"); + return std::array{static_cast(enum_min_value + I)... }; +#else + constexpr std::array valid { _is_valid(enum_min_value + I)>()... }; + constexpr auto valid_cnt { std::count_if(valid.cbegin(), valid.cend(), [](bool val) noexcept { return val; }) }; + static_assert(valid_cnt > 0, "conjure_enum requires non-empty enum"); + std::array vals{}; + for(std::size_t idx{}, nn{}; nn < valid_cnt; ++idx) + if (valid[idx]) + vals[nn++] = static_cast(enum_min_value + idx); + return vals; +#endif } template @@ -259,20 +255,19 @@ class conjure_enum final : public static_only constexpr auto ep { _epeek_v.rfind(cs::get_spec()) }; if constexpr (ep == std::string_view::npos) return {}; - if constexpr (!enum_flags::no_anon) +#if not defined FIX8_CONJURE_ENUM_NO_ANON + if constexpr (_epeek_v[ep + cs::get_spec().size()] == cs::get_spec()) { - if constexpr (_epeek_v[ep + cs::get_spec().size()] == cs::get_spec()) - { #if defined __clang__ - if constexpr (_epeek_v[ep + cs::get_spec().size() + 1] == cs::get_spec()) - return {}; + if constexpr (_epeek_v[ep + cs::get_spec().size() + 1] == cs::get_spec()) + return {}; #endif - if (constexpr auto lstr { _epeek_v.substr(ep + cs::get_spec().size()) }; - lstr.find(cs::get_spec()) != std::string_view::npos) // is anon - if constexpr (constexpr auto lc { lstr.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) - return lstr.substr(cs::get_spec().size() + 2, lc - (cs::get_spec().size() + 2)); // eat "::" - } + if (constexpr auto lstr { _epeek_v.substr(ep + cs::get_spec().size()) }; + lstr.find(cs::get_spec()) != std::string_view::npos) // is anon + if constexpr (constexpr auto lc { lstr.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) + return lstr.substr(cs::get_spec().size() + 2, lc - (cs::get_spec().size() + 2)); // eat "::" } +#endif constexpr std::string_view result { _epeek_v.substr(ep + cs::get_spec().size()) }; if constexpr (constexpr auto lc { result.find_first_of(cs::get_spec()) }; lc != std::string_view::npos) return result.substr(0, lc); From 05063f04b3fed726ac9830c8bef811a69d146154 Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 15 Aug 2024 06:23:54 +1000 Subject: [PATCH 083/235] pre-rel 1.0.2e --- include/fix8/conjure_enum.hpp | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 6fd8106..1155639 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -281,19 +281,6 @@ class conjure_enum final : public static_only template static constexpr auto _enum_name_v { fixed_string<_get_name_v.size()>(_get_name_v) }; - template - static constexpr auto _entries(std::index_sequence) noexcept - { - return std::array{{{ values[I], _enum_name_v}...}}; - } - - static constexpr auto _sorted_entries() noexcept - { - auto tmp { entries }; - std::sort(tmp.begin(), tmp.end(), _tuple_comp_rev); - return tmp; - } - /// comparators static constexpr bool _value_comp(const T& pl, const T& pr) noexcept { @@ -391,8 +378,15 @@ class conjure_enum final : public static_only // public constexpr data structures static constexpr auto values { _values(std::make_index_sequence()) }; - static constexpr auto entries { _entries(std::make_index_sequence()) }; - static constexpr auto sorted_entries { _sorted_entries() }; + static constexpr auto entries { [](std::index_sequence) noexcept + { return std::array{{{ values[I], _enum_name_v}...}};}(std::make_index_sequence()) }; + static constexpr auto sorted_entries { []() noexcept + { + auto tmp { entries }; + std::sort(tmp.begin(), tmp.end(), _tuple_comp_rev); + return tmp; + }()}; + // misc static constexpr int get_enum_min_value() noexcept { return enum_min_value; } From 65e5b03878b570979d80433838be4be688811623 Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 15 Aug 2024 06:27:08 +1000 Subject: [PATCH 084/235] pre-rel 1.0.2e --- include/fix8/conjure_enum.hpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 1155639..6fd8106 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -281,6 +281,19 @@ class conjure_enum final : public static_only template static constexpr auto _enum_name_v { fixed_string<_get_name_v.size()>(_get_name_v) }; + template + static constexpr auto _entries(std::index_sequence) noexcept + { + return std::array{{{ values[I], _enum_name_v}...}}; + } + + static constexpr auto _sorted_entries() noexcept + { + auto tmp { entries }; + std::sort(tmp.begin(), tmp.end(), _tuple_comp_rev); + return tmp; + } + /// comparators static constexpr bool _value_comp(const T& pl, const T& pr) noexcept { @@ -378,15 +391,8 @@ class conjure_enum final : public static_only // public constexpr data structures static constexpr auto values { _values(std::make_index_sequence()) }; - static constexpr auto entries { [](std::index_sequence) noexcept - { return std::array{{{ values[I], _enum_name_v}...}};}(std::make_index_sequence()) }; - static constexpr auto sorted_entries { []() noexcept - { - auto tmp { entries }; - std::sort(tmp.begin(), tmp.end(), _tuple_comp_rev); - return tmp; - }()}; - + static constexpr auto entries { _entries(std::make_index_sequence()) }; + static constexpr auto sorted_entries { _sorted_entries() }; // misc static constexpr int get_enum_min_value() noexcept { return enum_min_value; } From 63cf83432c3bf8e4840b522a8b743354fb34c556 Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 15 Aug 2024 06:27:37 +1000 Subject: [PATCH 085/235] pre-rel 1.0.2e --- include/fix8/conjure_enum.hpp | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 6fd8106..865f8f0 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -281,19 +281,6 @@ class conjure_enum final : public static_only template static constexpr auto _enum_name_v { fixed_string<_get_name_v.size()>(_get_name_v) }; - template - static constexpr auto _entries(std::index_sequence) noexcept - { - return std::array{{{ values[I], _enum_name_v}...}}; - } - - static constexpr auto _sorted_entries() noexcept - { - auto tmp { entries }; - std::sort(tmp.begin(), tmp.end(), _tuple_comp_rev); - return tmp; - } - /// comparators static constexpr bool _value_comp(const T& pl, const T& pr) noexcept { @@ -391,8 +378,10 @@ class conjure_enum final : public static_only // public constexpr data structures static constexpr auto values { _values(std::make_index_sequence()) }; - static constexpr auto entries { _entries(std::make_index_sequence()) }; - static constexpr auto sorted_entries { _sorted_entries() }; + static constexpr auto entries { [](std::index_sequence) noexcept + { return std::array{{{ values[I], _enum_name_v}...}};}(std::make_index_sequence()) }; + static constexpr auto sorted_entries { []() noexcept + { auto tmp { entries }; std::sort(tmp.begin(), tmp.end(), _tuple_comp_rev); return tmp; }()}; // misc static constexpr int get_enum_min_value() noexcept { return enum_min_value; } From 391370f172868db5c5beba5013c418515e368738 Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 15 Aug 2024 06:28:31 +1000 Subject: [PATCH 086/235] pre-rel 1.0.2e --- include/fix8/conjure_enum.hpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 865f8f0..6fd8106 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -281,6 +281,19 @@ class conjure_enum final : public static_only template static constexpr auto _enum_name_v { fixed_string<_get_name_v.size()>(_get_name_v) }; + template + static constexpr auto _entries(std::index_sequence) noexcept + { + return std::array{{{ values[I], _enum_name_v}...}}; + } + + static constexpr auto _sorted_entries() noexcept + { + auto tmp { entries }; + std::sort(tmp.begin(), tmp.end(), _tuple_comp_rev); + return tmp; + } + /// comparators static constexpr bool _value_comp(const T& pl, const T& pr) noexcept { @@ -378,10 +391,8 @@ class conjure_enum final : public static_only // public constexpr data structures static constexpr auto values { _values(std::make_index_sequence()) }; - static constexpr auto entries { [](std::index_sequence) noexcept - { return std::array{{{ values[I], _enum_name_v}...}};}(std::make_index_sequence()) }; - static constexpr auto sorted_entries { []() noexcept - { auto tmp { entries }; std::sort(tmp.begin(), tmp.end(), _tuple_comp_rev); return tmp; }()}; + static constexpr auto entries { _entries(std::make_index_sequence()) }; + static constexpr auto sorted_entries { _sorted_entries() }; // misc static constexpr int get_enum_min_value() noexcept { return enum_min_value; } From bccc70a097c02075489af757662c4db0df4f91bd Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 15 Aug 2024 06:35:55 +1000 Subject: [PATCH 087/235] pre-rel 1.0.2e --- include/fix8/conjure_enum.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 6fd8106..f67b15c 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -85,11 +85,11 @@ template class fixed_string final { const std::array _buff; - template - constexpr fixed_string(std::string_view sv, std::integer_sequence) noexcept : _buff{sv[C]..., 0} {} + template + constexpr fixed_string(std::string_view sv, std::index_sequence) noexcept : _buff{sv[C]..., 0} {} public: - explicit constexpr fixed_string(std::string_view sv) noexcept : fixed_string{sv, std::make_integer_sequence{}} {} + explicit constexpr fixed_string(std::string_view sv) noexcept : fixed_string{sv, std::make_index_sequence{}} {} constexpr fixed_string() = delete; constexpr std::string_view get() const noexcept { return { _buff.data(), N }; } constexpr operator std::string_view() const noexcept { return get(); } From 741c63513538be66564fb382eb42353028ab41eb Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 15 Aug 2024 06:55:54 +1000 Subject: [PATCH 088/235] pre-rel 1.0.2e --- include/fix8/conjure_enum.hpp | 10 ++++------ utests/unittests.cpp | 3 +++ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index f67b15c..e1ec164 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -82,19 +82,17 @@ using namespace std::literals::string_view_literals; //----------------------------------------------------------------------------------------- template -class fixed_string final +class fixed_string final : public std::array { - const std::array _buff; template - constexpr fixed_string(std::string_view sv, std::index_sequence) noexcept : _buff{sv[C]..., 0} {} + constexpr fixed_string(std::string_view sv, std::index_sequence) noexcept : std::array{sv[C]..., 0} {} public: explicit constexpr fixed_string(std::string_view sv) noexcept : fixed_string{sv, std::make_index_sequence{}} {} constexpr fixed_string() = delete; - constexpr std::string_view get() const noexcept { return { _buff.data(), N }; } + constexpr std::string_view get() const noexcept { return { this->data(), N }; } + constexpr const char *c_str() const noexcept { return this->data(); } constexpr operator std::string_view() const noexcept { return get(); } - constexpr char operator[](size_t idx) const noexcept { return _buff[idx]; } - constexpr std::size_t size() const noexcept { return _buff.size(); } friend std::ostream& operator<<(std::ostream& os, const fixed_string& what) noexcept { return os << what.get(); } }; diff --git a/utests/unittests.cpp b/utests/unittests.cpp index 71c7d66..cc0ce47 100644 --- a/utests/unittests.cpp +++ b/utests/unittests.cpp @@ -63,6 +63,9 @@ TEST_CASE("fixed_string") REQUIRE(f1.get().size() == t1.size()); // fixed_string as string_view REQUIRE(static_cast(f1) == t1); // fixed_string as string_view REQUIRE(static_cast(f1).size() == t1.size()); // fixed_string as string_view + std::ostringstream ostr; + ostr << f1.c_str(); + REQUIRE(ostr.str() == "The rain in Spain"); } //----------------------------------------------------------------------------------------- From 8931dd11f654cc597d44bd75b480478cffc3bc1e Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 15 Aug 2024 06:56:55 +1000 Subject: [PATCH 089/235] pre-rel 1.0.2e --- include/fix8/conjure_enum.hpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index e1ec164..c1fd61e 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -82,17 +82,20 @@ using namespace std::literals::string_view_literals; //----------------------------------------------------------------------------------------- template -class fixed_string final : public std::array +class fixed_string final { + const std::array _buff; template - constexpr fixed_string(std::string_view sv, std::index_sequence) noexcept : std::array{sv[C]..., 0} {} + constexpr fixed_string(std::string_view sv, std::index_sequence) noexcept : _buff{sv[C]..., 0} {} public: explicit constexpr fixed_string(std::string_view sv) noexcept : fixed_string{sv, std::make_index_sequence{}} {} constexpr fixed_string() = delete; - constexpr std::string_view get() const noexcept { return { this->data(), N }; } - constexpr const char *c_str() const noexcept { return this->data(); } + constexpr std::string_view get() const noexcept { return { _buff.data(), N }; } + constexpr const char *c_str() const noexcept { return _buff.data(); } constexpr operator std::string_view() const noexcept { return get(); } + constexpr char operator[](size_t idx) const noexcept { return _buff[idx]; } + constexpr std::size_t size() const noexcept { return _buff.size(); } friend std::ostream& operator<<(std::ostream& os, const fixed_string& what) noexcept { return os << what.get(); } }; From 34a8759ff6c095f5566f8abe266d25e4c44a3ba3 Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 15 Aug 2024 11:15:47 +1000 Subject: [PATCH 090/235] updated --- README.md | 66 +++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 59 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 4a50de5..11eda7d 100644 --- a/README.md +++ b/README.md @@ -50,9 +50,9 @@ |4|[`conjure_type` API and Examples](#5-api-and-examples-using-conjure_type)| Any type string extractor| |5|[Building](#6-building)| How to build or include| |6|[vcpkg](https://vcpkg.io/en/package/conjure-enum)| For vcpkg package| -|7|[Notes](#7-notes)| Notes on the implementation, limits, etc| -|8|[Compilers](#8-compiler-support)| Supported compilers| -|9|[Compiler issues](#9-compiler-issues)| Workarounds for various compiler issues| +|7|[Notes](#8-notes)| Notes on the implementation, limits, etc| +|8|[Compilers](#9-compiler-support)| Supported compilers| +|9|[Compiler issues](#10-compiler-issues)| Workarounds for various compiler issues| |10|[Results of `std::source_location`](reference/source_location.md)| For implementation specific `std::source_location` results| > [!TIP] > Use the built-in [table of contents](https://github.blog/changelog/2021-04-13-table-of-contents-support-in-markdown-files/) to navigate this guide. @@ -1252,7 +1252,59 @@ static consteval const char* FIX8::conjure_type::tpeek() [with T = test] ``` --- -# 6. Building +# 6. API for `fixed_string` +`fixed_string` is a specialisation of `std::array` that provides statics storage for an ASCII zero (asciiz) string. The purpose of this class is to allow the +creation of `constexpr` strings with specfic storage, adding a trailing `0`. It is used by `conjure_enum` to store all strings. API is described below. Other uses of this class are possible. + +## a) Creating a `fixed_string` +```c++ +template +class fixed_string; +constexpr fixed_string(std::string_view sv); +``` +Constructs a `fixed_string` from a `std::string_view`. Note the size must be passed as a template paramater. +```c++ +std::string_view sv{"The rain in Spain"}; +fixed_string fs{sv}; +``` + +## b) `get` +```c++ +constexpr std::string_view get() const; +``` +Returns the strings as a `std::string_view`; + +## c) `c_str` +```c++ +constexpr const char *c_str() const; +``` +Returns the strings as a null terminated `const char *`. + +## d) `c_str` +```c++ +constexpr operator std::string_view() const; +``` +Provides a `std::string_view` cast. + +## e) `c_str` +```c++ +constexpr char operator[](size_t idx) const; +``` + +## f) `size` +```c++ +constexpr std::size_t size() const; +``` +Returns the size of the `fixed_string` including the null terminator. + +## g) `std::ostream& operator<<` +```c++ +std::ostream& operator<<(std::ostream& os, const fixed_string& what) +``` +Provides an `ostream` insertor. + +--- +# 7. Building This implementation is header only. Apart from standard C++20 includes there are no external dependencies needed in your application. [Catch2](https://github.com/catchorg/Catch2.git) is used for the built-in unit tests. @@ -1387,7 +1439,7 @@ Contributions are welcome. Make your changes in [your fork on the dev branch](ht master will not be considered. --- -# 7. Notes +# 8. Notes ## a) enum limits ### i. `FIX8_CONJURE_ENUM_MIN_VALUE`, `FIX8_CONJURE_ENUM_MAX_VALUE` These are set by default unless you override them by defining them in your application. They are the global range default for enums using `conjure_enum`. @@ -1751,7 +1803,7 @@ Compilation (2 times):

--- -# 8. Compiler support +# 9. Compiler support | Compiler | Version(s) | Notes | Unsupported | | :--- | :--- | :--- | ---: | | [gcc](https://gcc.gnu.org/projects/cxx-status.html) | `11`, `12`, `13`, `14`| `std::format` not complete in `11`, `12` | `<= 10` | @@ -1759,7 +1811,7 @@ Compilation (2 times): | [msvc](https://learn.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance) | `16`, `17` | Visual Studio 2019,2022, latest `17.10.5`| `<= 16.9`| | [xcode](https://developer.apple.com/support/xcode/) | `15` | Apple LLVM 15.0.0, some issues with `constexpr`, workarounds| `<= 14`| -# 9. Compiler issues +# 10. Compiler issues | Compiler | Version(s) | Issues | Workaround | | :--- | :--- | :--- | ---: | | clang | `16`, `17`, `18`| Compiler reports integers outside valid range [x,y]| specify underlying type when declaring enum eg. `enum class foo : int` | From 7bcf539cdb9d0741449cf6d10aae8086bb08cd6e Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 15 Aug 2024 11:19:35 +1000 Subject: [PATCH 091/235] updated --- README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 11eda7d..79a1f17 100644 --- a/README.md +++ b/README.md @@ -1272,24 +1272,25 @@ fixed_string fs{sv}; ```c++ constexpr std::string_view get() const; ``` -Returns the strings as a `std::string_view`; +Returns the string as a `std::string_view`. ## c) `c_str` ```c++ constexpr const char *c_str() const; ``` -Returns the strings as a null terminated `const char *`. +Returns the string as a null terminated `const char *`. -## d) `c_str` +## d) `operator std::string_view` ```c++ constexpr operator std::string_view() const; ``` -Provides a `std::string_view` cast. +Provides a `std::string_view` cast. Returns the string as a `std::string_view`. -## e) `c_str` +## e) `operator[]` ```c++ constexpr char operator[](size_t idx) const; ``` +Returns the character at the specifdined index. It is not range checked. ## f) `size` ```c++ From 65a7566c01c5aff98820bb06d02b7d70f0d10ac7 Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 15 Aug 2024 11:23:56 +1000 Subject: [PATCH 092/235] updated --- README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 79a1f17..72f99d3 100644 --- a/README.md +++ b/README.md @@ -48,12 +48,13 @@ |2|[`conjure_enum` API and Examples](#3-api-and-examples-using-conjure_enum)| General examples| |3|[`enum_bitset` API and Examples](#4-api-and-examples-using-enum_bitset)| Enhanced enum aware `std::bitset`| |4|[`conjure_type` API and Examples](#5-api-and-examples-using-conjure_type)| Any type string extractor| -|5|[Building](#6-building)| How to build or include| -|6|[vcpkg](https://vcpkg.io/en/package/conjure-enum)| For vcpkg package| -|7|[Notes](#8-notes)| Notes on the implementation, limits, etc| -|8|[Compilers](#9-compiler-support)| Supported compilers| -|9|[Compiler issues](#10-compiler-issues)| Workarounds for various compiler issues| -|10|[Results of `std::source_location`](reference/source_location.md)| For implementation specific `std::source_location` results| +|5|[`fixed_string` API](#6-api-for-fixed-string)| Fixed string| +|6|[Building](#7-building)| How to build or include| +|7|[vcpkg](https://vcpkg.io/en/package/conjure-enum)| For vcpkg package| +|8|[Notes](#8-notes)| Notes on the implementation, limits, etc| +|9|[Compilers](#9-compiler-support)| Supported compilers| +|10|[Compiler issues](#10-compiler-issues)| Workarounds for various compiler issues| +|11|[Results of `std::source_location`](reference/source_location.md)| For implementation specific `std::source_location` results| > [!TIP] > Use the built-in [table of contents](https://github.blog/changelog/2021-04-13-table-of-contents-support-in-markdown-files/) to navigate this guide. > Even better in [full read view](./README.md) of this page. From bb06db57d6a863a44b7c1229aa39557ce68911c6 Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 15 Aug 2024 11:25:04 +1000 Subject: [PATCH 093/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 72f99d3..0eaa9f7 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ |2|[`conjure_enum` API and Examples](#3-api-and-examples-using-conjure_enum)| General examples| |3|[`enum_bitset` API and Examples](#4-api-and-examples-using-enum_bitset)| Enhanced enum aware `std::bitset`| |4|[`conjure_type` API and Examples](#5-api-and-examples-using-conjure_type)| Any type string extractor| -|5|[`fixed_string` API](#6-api-for-fixed-string)| Fixed string| +|5|[`fixed_string` API](#6-api-for-fixed_string)| Statically stored fixed string| |6|[Building](#7-building)| How to build or include| |7|[vcpkg](https://vcpkg.io/en/package/conjure-enum)| For vcpkg package| |8|[Notes](#8-notes)| Notes on the implementation, limits, etc| From 3ae9d9462efd94973f7d19ce320302bf503f1e3b Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 15 Aug 2024 11:35:00 +1000 Subject: [PATCH 094/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0eaa9f7..606ebaf 100644 --- a/README.md +++ b/README.md @@ -1263,7 +1263,7 @@ template class fixed_string; constexpr fixed_string(std::string_view sv); ``` -Constructs a `fixed_string` from a `std::string_view`. Note the size must be passed as a template paramater. +Constructs a `fixed_string` from a `std::string_view`. The source string is _copied_ and a null character is added to the end. Note the size of the _source_ string must be passed as a template paramater. ```c++ std::string_view sv{"The rain in Spain"}; fixed_string fs{sv}; From 0602a3e7617e8e004702714baf1fe525d038fd60 Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 15 Aug 2024 11:37:35 +1000 Subject: [PATCH 095/235] updated --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 606ebaf..8fe1554 100644 --- a/README.md +++ b/README.md @@ -1263,10 +1263,10 @@ template class fixed_string; constexpr fixed_string(std::string_view sv); ``` -Constructs a `fixed_string` from a `std::string_view`. The source string is _copied_ and a null character is added to the end. Note the size of the _source_ string must be passed as a template paramater. +Constructs a `fixed_string` from a `std::string_view`. The source string is _copied_ and a null character is added to the end. Note the size of the _source_ string must be passed as a template parameter. ```c++ std::string_view sv{"The rain in Spain"}; -fixed_string fs{sv}; +constexpr fixed_string fs{sv}; ``` ## b) `get` From e434165a566253b2f1aac4ff20ec9dbea30be522 Mon Sep 17 00:00:00 2001 From: David Dight Date: Fri, 16 Aug 2024 07:17:42 +1000 Subject: [PATCH 096/235] pre-rel 1.0.2e --- include/fix8/conjure_enum.hpp | 40 +++++++++++++++++++++++++++-------- utests/unittests.cpp | 2 +- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index c1fd61e..9fb1ee2 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -85,8 +85,8 @@ template class fixed_string final { const std::array _buff; - template - constexpr fixed_string(std::string_view sv, std::index_sequence) noexcept : _buff{sv[C]..., 0} {} + template + constexpr fixed_string(std::string_view sv, std::index_sequence) noexcept : _buff{sv[I]..., 0} {} public: explicit constexpr fixed_string(std::string_view sv) noexcept : fixed_string{sv, std::make_index_sequence{}} {} @@ -125,13 +125,13 @@ class cs final : public static_only std::to_array> ({ #if defined __clang__ - { "e = "sv, ']', "(anonymous namespace)"sv, '(' }, { "T = "sv, ']', "(anonymous namespace)"sv, '(' }, + { "e = ", ']', "(anonymous namespace)", '(' }, { "T = ", ']', "(anonymous namespace)", '(' }, #elif defined __GNUC__ - { "e = "sv, ';', ""sv, '<' }, { "T = "sv, ']', "{anonymous}"sv, '{' }, + { "e = ", ';', "", '<' }, { "T = ", ']', "{anonymous}", '{' }, #elif defined _MSC_VER - { "epeek<"sv, '>', "`anonymous-namespace'"sv, '`' }, { "::tpeek"sv, '<', "enum `anonymous namespace'::"sv, '\0' }, - { ""sv, '\0', "`anonymous namespace'::"sv, '\0' }, { ""sv, '\0', "enum "sv, '\0' }, { ""sv, '\0', "class "sv, '\0' }, - { ""sv, '\0', "struct "sv, '\0' }, + { "epeek<", '>', "`anonymous-namespace'", '`' }, { "::tpeek", '<', "enum `anonymous namespace'::", '\0' }, + { "", '\0', "`anonymous namespace'::", '\0' }, { "", '\0', "enum ", '\0' }, { "", '\0', "class ", '\0' }, + { "", '\0', "struct ", '\0' }, #else # error "conjure_enum not supported by your compiler" #endif @@ -179,7 +179,7 @@ struct enum_range final : public static_only // Convenience macros for above //----------------------------------------------------------------------------------------- #define FIX8_CONJURE_ENUM_SET_RANGE_INTS(ec,minv,maxv) \ - template<> struct FIX8::enum_range { static constexpr int min{minv}, max{maxv}; }; + template<> struct FIX8::enum_range final { static constexpr int min{minv}, max{maxv}; }; #define FIX8_CONJURE_ENUM_SET_RANGE(minv,maxv) \ FIX8_CONJURE_ENUM_SET_RANGE_INTS(decltype(minv),static_cast(minv), static_cast(maxv)) @@ -319,6 +319,7 @@ class conjure_enum final : public static_only static constexpr bool is_valid() noexcept { return contains(); } static constexpr auto count() noexcept { return values.size(); } + static constexpr bool is_continuous() noexcept { return (enum_max_value - enum_min_value + 1) == count(); } // scope ops static constexpr bool has_scope(std::string_view what) noexcept @@ -340,6 +341,8 @@ class conjure_enum final : public static_only } static constexpr std::optional int_to_enum(int value) noexcept { + if constexpr (is_continuous()) + return in_range(static_cast(value)) ? static_cast(value) : std::optional{}; if (const auto [begin,end] { std::equal_range(values.cbegin(), values.cend(), static_cast(value), _value_comp) }; begin != end) return *begin; @@ -349,6 +352,8 @@ class conjure_enum final : public static_only // index static constexpr std::optional index(T value) noexcept { + if constexpr (is_continuous()) + return in_range(value) ? to_underlying(value) - to_underlying(min_v) : std::optional{}; const auto [begin,end] { std::equal_range(entries.cbegin(), entries.cend(), enum_tuple(value, std::string_view()), _tuple_comp) }; return begin != end ? &*begin - &*entries.cbegin() : std::optional{}; } @@ -358,6 +363,8 @@ class conjure_enum final : public static_only // contains static constexpr bool contains(T value) noexcept { + if constexpr (is_continuous()) + return in_range(value); return std::binary_search(values.cbegin(), values.cend(), value, _value_comp); } static constexpr bool contains(std::string_view str) noexcept @@ -371,9 +378,22 @@ class conjure_enum final : public static_only template static constexpr std::string_view enum_to_string() noexcept { return _get_name_v; } + static constexpr bool in_range(T value) noexcept { return min_v <= value && value <= max_v; } static constexpr std::string_view enum_to_string(T value, [[maybe_unused]] bool noscope=false) noexcept { - if (const auto [begin,end] { std::equal_range(entries.cbegin(), entries.cend(), enum_tuple(value, std::string_view()), _tuple_comp) }; + if constexpr (is_continuous()) + { + if (in_range(value)) + { +#if not defined FIX8_CONJURE_ENUM_MINIMAL + if (noscope) + return remove_scope(std::get(entries[enum_to_underlying(value)])); + else +#endif + return std::get(entries[enum_to_underlying(value)]); + } + } + else if (const auto [begin,end] { std::equal_range(entries.cbegin(), entries.cend(), enum_tuple(value, std::string_view()), _tuple_comp) }; begin != end) { #if not defined FIX8_CONJURE_ENUM_MINIMAL @@ -398,6 +418,8 @@ class conjure_enum final : public static_only // misc static constexpr int get_enum_min_value() noexcept { return enum_min_value; } static constexpr int get_enum_max_value() noexcept { return enum_max_value; } + static constexpr auto min_v { values.front() }; + static constexpr auto max_v { values.back() }; #if not defined FIX8_CONJURE_ENUM_MINIMAL #include diff --git a/utests/unittests.cpp b/utests/unittests.cpp index cc0ce47..ec304e0 100644 --- a/utests/unittests.cpp +++ b/utests/unittests.cpp @@ -57,7 +57,7 @@ enum class range_test2 { first, second, third, fourth, fifth, sixth, seventh, ei TEST_CASE("fixed_string") { static constexpr std::string_view t1{"The rain in Spain"}; - fixed_string f1{t1}; + constexpr fixed_string f1{t1}; REQUIRE(f1.size() == t1.size() + 1); // fixed_string makes string ASCIIZ REQUIRE(f1[t1.size()] == 0); // test ASCIIZ REQUIRE(f1.get().size() == t1.size()); // fixed_string as string_view From d8686ddf6c408a3473c40de9aa87c8872762a67b Mon Sep 17 00:00:00 2001 From: David Dight Date: Fri, 16 Aug 2024 07:43:54 +1000 Subject: [PATCH 097/235] updated --- README.md | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 8fe1554..bf81d8e 100644 --- a/README.md +++ b/README.md @@ -425,24 +425,28 @@ _output_ 4 100 <-- invalid, error value ``` -## n) `contains` +## n) `contains`, `is_valid` ```c++ static constexpr bool contains(T value); static constexpr bool contains(std::string_view str); template static constexpr bool contains(); +template +static constexpr bool is_valid(); ``` Returns `true` if the enum contains the given value or string. ```c++ std::cout << std::format("{}\n", conjure_enum::contains(component::path)); std::cout << std::format("{}\n", conjure_enum::contains("nothing")); std::cout << std::format("{}\n", conjure_enum::contains()); +std::cout << std::format("{}\n", conjure_enum::is_valid()); ``` _output_ ```CSV true false true +true ``` ## o) `for_each`, `for_each_n` ![](assets/notminimalred.svg) ```c++ @@ -662,15 +666,14 @@ _output_ true false ``` -## r) `is_valid` +## r) `is_continuous` ```c++ -template -static constexpr bool is_valid(); +static constexpr bool is_continuous(); ``` -Returns `true` if enum value is valid. +Returns `true` if enum range is continuous (no gaps). ```c++ -std::cout << std::format("{}\n", conjure_enum::is_valid()); -std::cout << std::format("{}\n", conjure_enum::is_valid(16)>()); +std::cout << std::format("{}\n", conjure_enum::is_continuous()); +std::cout << std::format("{}\n", conjure_enum::is_continuous()); ``` _output_ ```CSV @@ -858,6 +861,20 @@ _output_ ```CSV -128/127 ``` + +## C) `in_range` +```c++ +static constexpr bool in_range(T value); +``` +Returns `true` if the given value is within the minimum and maximum defined values for this enum type. +```c++ +std::cout << std::format("{}\n", conjure_enum::in_range(static_cast(100))); +``` +_output_ +```CSV +false +``` + --- # 4. API and Examples using `enum_bitset` `enum_bitset` is a convenient way of creating bitsets based on `std::bitset`. It uses your enum (scoped or unscoped) From 86a8ebbe8bb7bd906ab21afcfd5f5a3869386f1b Mon Sep 17 00:00:00 2001 From: David Dight Date: Fri, 16 Aug 2024 07:49:54 +1000 Subject: [PATCH 098/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bf81d8e..553a34d 100644 --- a/README.md +++ b/README.md @@ -1827,7 +1827,7 @@ Compilation (2 times): | :--- | :--- | :--- | ---: | | [gcc](https://gcc.gnu.org/projects/cxx-status.html) | `11`, `12`, `13`, `14`| `std::format` not complete in `11`, `12` | `<= 10` | | [clang](https://clang.llvm.org/cxx_status.html) | `15`, `16`, `17`, `18`| Catch2 needs `cxx_std_20` in `15` | `<= 14` | -| [msvc](https://learn.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance) | `16`, `17` | Visual Studio 2019,2022, latest `17.10.5`| `<= 16.9`| +| [msvc](https://learn.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance) | `16`, `17` | Visual Studio 2019,2022, latest `17.11.0`| `<= 16.9`| | [xcode](https://developer.apple.com/support/xcode/) | `15` | Apple LLVM 15.0.0, some issues with `constexpr`, workarounds| `<= 14`| # 10. Compiler issues From 4775c70ed7c470e9893a8bb616a7c1de2ec76b6a Mon Sep 17 00:00:00 2001 From: David Dight Date: Fri, 16 Aug 2024 10:38:36 +1000 Subject: [PATCH 099/235] updated --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 553a34d..231e9a5 100644 --- a/README.md +++ b/README.md @@ -847,19 +847,24 @@ static consteval const char* FIX8::conjure_enum::tpeek() [with T = component] static consteval const char* FIX8::conjure_enum::epeek() [with T e = component::path; T = component] ``` -## B) `get_enum_min_value` and `get_enum_max_value` +## B) `get_enum_min_value`, `get_enum_max_value`, `get_enum_min_actual_value` and `get_enum_max_actual_value` ```c++ static constexpr int get_enum_min_value(); static constexpr int get_enum_max_value(); +static constexpr int get_enum_min_actual_value(); +static constexpr int get_enum_max_actual_value(); ``` -These functions return the min and max enum range for the specified enum. If you have specialised `enum_range` then these values +The first two functions return the min and max enum range for the specified enum. If you have specialised `enum_range` then these values will be reported (see below). +The second two functions return the actual min and max enum values as ints for the specified enum. ```c++ std::cout << conjure_enum::get_enum_min_value() << '/' << conjure_enum::get_enum_min_value() << '\n'; +std::cout << conjure_enum::get_enum_min_actual_value() << '/' << conjure_enum::get_enum_min_actual_value() << '\n'; ``` _output_ ```CSV -128/127 +0/14 ``` ## C) `in_range` From ef6915b7e7c641b86506069e188d4de1c2c41312 Mon Sep 17 00:00:00 2001 From: David Dight Date: Fri, 16 Aug 2024 10:56:24 +1000 Subject: [PATCH 100/235] pre-rel 1.1.0a --- include/fix8/conjure_enum.hpp | 17 +++++++++-------- include/fix8/conjure_enum_ext.hpp | 10 +++++----- utests/unittests.cpp | 27 +++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 13 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 9fb1ee2..50a4e78 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -315,11 +315,9 @@ class conjure_enum final : public static_only requires !std::convertible_to>; }>{}; - template - static constexpr bool is_valid() noexcept { return contains(); } - static constexpr auto count() noexcept { return values.size(); } - static constexpr bool is_continuous() noexcept { return (enum_max_value - enum_min_value + 1) == count(); } + static constexpr bool is_continuous() noexcept { return (static_cast(max_v) - static_cast(min_v) + 1) == count(); } + static constexpr bool in_range(T value) noexcept { return std::clamp(value, min_v, max_v) == value; } // scope ops static constexpr bool has_scope(std::string_view what) noexcept @@ -353,7 +351,7 @@ class conjure_enum final : public static_only static constexpr std::optional index(T value) noexcept { if constexpr (is_continuous()) - return in_range(value) ? to_underlying(value) - to_underlying(min_v) : std::optional{}; + return in_range(value) ? enum_to_underlying(value) - enum_to_underlying(min_v) : std::optional{}; const auto [begin,end] { std::equal_range(entries.cbegin(), entries.cend(), enum_tuple(value, std::string_view()), _tuple_comp) }; return begin != end ? &*begin - &*entries.cbegin() : std::optional{}; } @@ -361,6 +359,9 @@ class conjure_enum final : public static_only static constexpr std::optional index() noexcept { return index(e); } // contains + template + static constexpr bool is_valid() noexcept { return contains(); } + static constexpr bool contains(T value) noexcept { if constexpr (is_continuous()) @@ -378,7 +379,6 @@ class conjure_enum final : public static_only template static constexpr std::string_view enum_to_string() noexcept { return _get_name_v; } - static constexpr bool in_range(T value) noexcept { return min_v <= value && value <= max_v; } static constexpr std::string_view enum_to_string(T value, [[maybe_unused]] bool noscope=false) noexcept { if constexpr (is_continuous()) @@ -388,7 +388,6 @@ class conjure_enum final : public static_only #if not defined FIX8_CONJURE_ENUM_MINIMAL if (noscope) return remove_scope(std::get(entries[enum_to_underlying(value)])); - else #endif return std::get(entries[enum_to_underlying(value)]); } @@ -412,7 +411,7 @@ class conjure_enum final : public static_only // public constexpr data structures static constexpr auto values { _values(std::make_index_sequence()) }; - static constexpr auto entries { _entries(std::make_index_sequence()) }; + static constexpr auto entries { _entries(std::make_index_sequence()) }; static constexpr auto sorted_entries { _sorted_entries() }; // misc @@ -420,6 +419,8 @@ class conjure_enum final : public static_only static constexpr int get_enum_max_value() noexcept { return enum_max_value; } static constexpr auto min_v { values.front() }; static constexpr auto max_v { values.back() }; + static constexpr int get_enum_min_actual_value() noexcept { return static_cast(min_v); } + static constexpr int get_enum_max_actual_value() noexcept { return static_cast(max_v); } #if not defined FIX8_CONJURE_ENUM_MINIMAL #include diff --git a/include/fix8/conjure_enum_ext.hpp b/include/fix8/conjure_enum_ext.hpp index 7b980c2..43da329 100644 --- a/include/fix8/conjure_enum_ext.hpp +++ b/include/fix8/conjure_enum_ext.hpp @@ -223,11 +223,11 @@ } // public constexpr data structures - static constexpr auto names { _names(std::make_index_sequence()) }; - static constexpr auto scoped_entries { _scoped_entries(std::make_index_sequence()) }; - static constexpr auto unscoped_entries { _unscoped_entries(std::make_index_sequence()) }; - static constexpr auto rev_scoped_entries { _rev_scoped_entries(std::make_index_sequence()) }; - static constexpr auto unscoped_names { _unscoped_names(std::make_index_sequence()) }; + static constexpr auto names { _names(std::make_index_sequence()) }; + static constexpr auto scoped_entries { _scoped_entries(std::make_index_sequence()) }; + static constexpr auto unscoped_entries { _unscoped_entries(std::make_index_sequence()) }; + static constexpr auto rev_scoped_entries { _rev_scoped_entries(std::make_index_sequence()) }; + static constexpr auto unscoped_names { _unscoped_names(std::make_index_sequence()) }; }; //----------------------------------------------------------------------------------------- diff --git a/utests/unittests.cpp b/utests/unittests.cpp index ec304e0..b78a245 100644 --- a/utests/unittests.cpp +++ b/utests/unittests.cpp @@ -73,6 +73,8 @@ TEST_CASE("default range") { REQUIRE(conjure_enum::get_enum_min_value() == FIX8_CONJURE_ENUM_MIN_VALUE); REQUIRE(conjure_enum::get_enum_max_value() == FIX8_CONJURE_ENUM_MAX_VALUE); + REQUIRE(conjure_enum::get_enum_min_actual_value() == 0); + REQUIRE(conjure_enum::get_enum_max_actual_value() == 14); } //----------------------------------------------------------------------------------------- @@ -88,6 +90,8 @@ TEST_CASE("custom range") { REQUIRE(conjure_enum::get_enum_min_value() == 0); REQUIRE(conjure_enum::get_enum_max_value() == 7); + REQUIRE(conjure_enum::get_enum_min_value() == conjure_enum::get_enum_min_actual_value()); + REQUIRE(conjure_enum::get_enum_max_value() == conjure_enum::get_enum_max_actual_value()); REQUIRE(conjure_enum::get_enum_min_value() == 0); REQUIRE(conjure_enum::get_enum_max_value() == 7); REQUIRE(conjure_enum::get_enum_min_value() == 0); @@ -110,11 +114,28 @@ TEST_CASE("is_scoped") REQUIRE(!conjure_enum::is_scoped()); } +//----------------------------------------------------------------------------------------- +TEST_CASE("is_continuous") +{ + REQUIRE(!conjure_enum::is_continuous()); + REQUIRE(conjure_enum::is_continuous()); +} + //----------------------------------------------------------------------------------------- TEST_CASE("count") { REQUIRE(conjure_enum::count() == 10); REQUIRE(conjure_enum::count() == 10); + REQUIRE(conjure_enum::count() == 10); +} + +//----------------------------------------------------------------------------------------- +TEST_CASE("in_range") +{ + REQUIRE(conjure_enum::in_range(component::password)); + REQUIRE(!conjure_enum::in_range(static_cast(100))); + REQUIRE(conjure_enum::in_range(numbers::five)); + REQUIRE(!conjure_enum::in_range(static_cast(100))); } //----------------------------------------------------------------------------------------- @@ -220,6 +241,8 @@ TEST_CASE("contains") REQUIRE(conjure_enum::contains()); REQUIRE(conjure_enum::contains()); // alias REQUIRE(conjure_enum::contains()); + REQUIRE(conjure_enum::contains(numbers::five)); + REQUIRE(!conjure_enum::contains(static_cast(100))); } //----------------------------------------------------------------------------------------- @@ -301,6 +324,8 @@ TEST_CASE("int_to_enum") REQUIRE(conjure_enum::int_to_enum(4).value() == password); REQUIRE(conjure_enum::int_to_enum(11).value_or(static_cast(100)) == static_cast(100)); REQUIRE(conjure_enum::int_to_enum(11).value_or(static_cast(100)) == static_cast(100)); + REQUIRE(conjure_enum::int_to_enum(4).value() == numbers::four); + REQUIRE(conjure_enum::int_to_enum(11).value_or(static_cast(100)) == static_cast(100)); } //----------------------------------------------------------------------------------------- @@ -323,6 +348,8 @@ TEST_CASE("index") REQUIRE(conjure_enum::index().value() == 4); REQUIRE(conjure_enum::index().value() == 8); REQUIRE(conjure_enum::index().value_or(100) == 100); + REQUIRE(conjure_enum::index().value() == 5); + REQUIRE(conjure_enum::index().value_or(100) == 100); } //----------------------------------------------------------------------------------------- From e9fc190eeae648f7e9e54811e8b8622abc0a6779 Mon Sep 17 00:00:00 2001 From: David Dight Date: Fri, 16 Aug 2024 15:18:30 +1000 Subject: [PATCH 101/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 231e9a5..a6a5948 100644 --- a/README.md +++ b/README.md @@ -591,7 +591,7 @@ If you wish to pass a `reference` parameter, you must wrap it in `std::ref`. If you wish to provide a `constexpr` array, you will need to use a simple function prototype, since `std::function` is not constexpr (see unit tests for examples). > [!IMPORTANT] > Your `std::array` of `std::tuple` should be sorted by enum. -> The `dispatch` method performs a binary search on the array. Complexity for a sorted array is at most $2log_2(N)+O(1)$ comparisons. +> The `dispatch` method performs a binary search on the array. Complexity for a sorted array is at most $2log_2(N)+O(1)$ comparisons. > If the array is _not_ sorted, complexity is linear. ```c++ enum class directions { left, right, up, down, forward, backward, notfound=-1 }; From 46e9f70beac53aaaf93bb12accfb5d7036adf295 Mon Sep 17 00:00:00 2001 From: David Dight Date: Fri, 16 Aug 2024 15:19:45 +1000 Subject: [PATCH 102/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a6a5948..a03b0f7 100644 --- a/README.md +++ b/README.md @@ -591,7 +591,7 @@ If you wish to pass a `reference` parameter, you must wrap it in `std::ref`. If you wish to provide a `constexpr` array, you will need to use a simple function prototype, since `std::function` is not constexpr (see unit tests for examples). > [!IMPORTANT] > Your `std::array` of `std::tuple` should be sorted by enum. -> The `dispatch` method performs a binary search on the array. Complexity for a sorted array is at most $2log_2(N)+O(1)$ comparisons. +> The `dispatch` method performs a binary search on the array. Complexity for a sorted array is at most $`2log_2(N)+O(1)`$ comparisons. > If the array is _not_ sorted, complexity is linear. ```c++ enum class directions { left, right, up, down, forward, backward, notfound=-1 }; From c88ff4805d1b3abeb63d379c1317985625725fe5 Mon Sep 17 00:00:00 2001 From: David Dight Date: Fri, 16 Aug 2024 15:20:06 +1000 Subject: [PATCH 103/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a03b0f7..892bd71 100644 --- a/README.md +++ b/README.md @@ -591,7 +591,7 @@ If you wish to pass a `reference` parameter, you must wrap it in `std::ref`. If you wish to provide a `constexpr` array, you will need to use a simple function prototype, since `std::function` is not constexpr (see unit tests for examples). > [!IMPORTANT] > Your `std::array` of `std::tuple` should be sorted by enum. -> The `dispatch` method performs a binary search on the array. Complexity for a sorted array is at most $`2log_2(N)+O(1)`$ comparisons. +> The `dispatch` method performs a binary search on the array. Complexity for a sorted array is at most $` 2log_2(N)+O(1) `$ comparisons. > If the array is _not_ sorted, complexity is linear. ```c++ enum class directions { left, right, up, down, forward, backward, notfound=-1 }; From 8a8266fe9d8f569e831bc7197c1ce9604b3316ca Mon Sep 17 00:00:00 2001 From: David Dight Date: Fri, 16 Aug 2024 15:21:53 +1000 Subject: [PATCH 104/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 892bd71..d47d60c 100644 --- a/README.md +++ b/README.md @@ -591,7 +591,7 @@ If you wish to pass a `reference` parameter, you must wrap it in `std::ref`. If you wish to provide a `constexpr` array, you will need to use a simple function prototype, since `std::function` is not constexpr (see unit tests for examples). > [!IMPORTANT] > Your `std::array` of `std::tuple` should be sorted by enum. -> The `dispatch` method performs a binary search on the array. Complexity for a sorted array is at most $` 2log_2(N)+O(1) `$ comparisons. +> The `dispatch` method performs a binary search on the array. Complexity for a sorted array is at most  $2log_2(N)+O(1)$  comparisons. > If the array is _not_ sorted, complexity is linear. ```c++ enum class directions { left, right, up, down, forward, backward, notfound=-1 }; From b3e0ae916636d1b1dff9fc43055ab99e7d4a07ef Mon Sep 17 00:00:00 2001 From: David Dight Date: Fri, 16 Aug 2024 15:22:16 +1000 Subject: [PATCH 105/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d47d60c..9d56a5e 100644 --- a/README.md +++ b/README.md @@ -591,7 +591,7 @@ If you wish to pass a `reference` parameter, you must wrap it in `std::ref`. If you wish to provide a `constexpr` array, you will need to use a simple function prototype, since `std::function` is not constexpr (see unit tests for examples). > [!IMPORTANT] > Your `std::array` of `std::tuple` should be sorted by enum. -> The `dispatch` method performs a binary search on the array. Complexity for a sorted array is at most  $2log_2(N)+O(1)$  comparisons. +> The `dispatch` method performs a binary search on the array. Complexity for a sorted array is at most  $2log_2(N)+O(1)$  comparisons. > If the array is _not_ sorted, complexity is linear. ```c++ enum class directions { left, right, up, down, forward, backward, notfound=-1 }; From 278680ac95a6e44e8b6606df3e67af6f3f963992 Mon Sep 17 00:00:00 2001 From: David Dight Date: Fri, 16 Aug 2024 16:08:23 +1000 Subject: [PATCH 106/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9d56a5e..0017050 100644 --- a/README.md +++ b/README.md @@ -591,7 +591,7 @@ If you wish to pass a `reference` parameter, you must wrap it in `std::ref`. If you wish to provide a `constexpr` array, you will need to use a simple function prototype, since `std::function` is not constexpr (see unit tests for examples). > [!IMPORTANT] > Your `std::array` of `std::tuple` should be sorted by enum. -> The `dispatch` method performs a binary search on the array. Complexity for a sorted array is at most  $2log_2(N)+O(1)$  comparisons. +> The `dispatch` method performs a binary search on the array. Complexity for a sorted array is at most  $2log_2(N)+O(1)$  comparisons. > If the array is _not_ sorted, complexity is linear. ```c++ enum class directions { left, right, up, down, forward, backward, notfound=-1 }; From 740ccb624d04768e3d3dccb147e467926b347dfe Mon Sep 17 00:00:00 2001 From: David Dight Date: Fri, 16 Aug 2024 16:54:04 +1000 Subject: [PATCH 107/235] pre-rel 1.1.0a --- include/fix8/conjure_enum.hpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 50a4e78..de08b1f 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -339,12 +339,7 @@ class conjure_enum final : public static_only } static constexpr std::optional int_to_enum(int value) noexcept { - if constexpr (is_continuous()) - return in_range(static_cast(value)) ? static_cast(value) : std::optional{}; - if (const auto [begin,end] { std::equal_range(values.cbegin(), values.cend(), static_cast(value), _value_comp) }; - begin != end) - return *begin; - return {}; + return contains(static_cast(value)) ? static_cast(value) : std::optional{}; } // index From 06d17371aaae706fb2493d17a25a1e3dd86bf494 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sat, 17 Aug 2024 06:39:27 +1000 Subject: [PATCH 108/235] updated --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 0017050..e3737e4 100644 --- a/README.md +++ b/README.md @@ -847,19 +847,19 @@ static consteval const char* FIX8::conjure_enum::tpeek() [with T = component] static consteval const char* FIX8::conjure_enum::epeek() [with T e = component::path; T = component] ``` -## B) `get_enum_min_value`, `get_enum_max_value`, `get_enum_min_actual_value` and `get_enum_max_actual_value` +## B) `get_enum_min_value`, `get_enum_max_value`, `get_actual_enum_min_value` and `get_actual_enum_max_value` ```c++ static constexpr int get_enum_min_value(); static constexpr int get_enum_max_value(); -static constexpr int get_enum_min_actual_value(); -static constexpr int get_enum_max_actual_value(); +static constexpr int get_actual_enum_min_value(); +static constexpr int get_actual_enum_max_value(); ``` The first two functions return the min and max enum range for the specified enum. If you have specialised `enum_range` then these values will be reported (see below). The second two functions return the actual min and max enum values as ints for the specified enum. ```c++ std::cout << conjure_enum::get_enum_min_value() << '/' << conjure_enum::get_enum_min_value() << '\n'; -std::cout << conjure_enum::get_enum_min_actual_value() << '/' << conjure_enum::get_enum_min_actual_value() << '\n'; +std::cout << conjure_enum::get_actual_enum_min_value() << '/' << conjure_enum::get_actual_enum_min_value() << '\n'; ``` _output_ ```CSV @@ -885,7 +885,7 @@ false `enum_bitset` is a convenient way of creating bitsets based on `std::bitset`. It uses your enum (scoped or unscoped) for the bit positions (and names). > [!WARNING] -> Your enum _must_ be continuous. The last value must be less than the count of enumerations. +> Your enum sequence _must_ be 0 based, continuous and the last value must be less than the count of enumerations. > We decided on this restriction for both simplicity and practicality - bitsets only really make sense when represented in this manner. > [!IMPORTANT] From 854ebf247d5ef892fe2b00b2271b1322ab91f22d Mon Sep 17 00:00:00 2001 From: David Dight Date: Sat, 17 Aug 2024 06:40:24 +1000 Subject: [PATCH 109/235] updated --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e3737e4..d18c601 100644 --- a/README.md +++ b/README.md @@ -885,7 +885,9 @@ false `enum_bitset` is a convenient way of creating bitsets based on `std::bitset`. It uses your enum (scoped or unscoped) for the bit positions (and names). > [!WARNING] -> Your enum sequence _must_ be 0 based, continuous and the last value must be less than the count of enumerations. +> - Your enum sequence _must_ be 0 based +> - Continuous +> - The last value must be less than the count of enumerations > We decided on this restriction for both simplicity and practicality - bitsets only really make sense when represented in this manner. > [!IMPORTANT] From 742fb1df168d9426067c28dcaea6def81041c39c Mon Sep 17 00:00:00 2001 From: David Dight Date: Sat, 17 Aug 2024 06:40:46 +1000 Subject: [PATCH 110/235] updated --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d18c601..0bc6b57 100644 --- a/README.md +++ b/README.md @@ -888,6 +888,7 @@ for the bit positions (and names). > - Your enum sequence _must_ be 0 based > - Continuous > - The last value must be less than the count of enumerations +> > We decided on this restriction for both simplicity and practicality - bitsets only really make sense when represented in this manner. > [!IMPORTANT] From 46ad8ca9d0af9896e1d985ed95c58626e61f3cc5 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sat, 17 Aug 2024 07:44:18 +1000 Subject: [PATCH 111/235] updated --- README.md | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 0bc6b57..6795492 100644 --- a/README.md +++ b/README.md @@ -52,9 +52,10 @@ |6|[Building](#7-building)| How to build or include| |7|[vcpkg](https://vcpkg.io/en/package/conjure-enum)| For vcpkg package| |8|[Notes](#8-notes)| Notes on the implementation, limits, etc| -|9|[Compilers](#9-compiler-support)| Supported compilers| -|10|[Compiler issues](#10-compiler-issues)| Workarounds for various compiler issues| -|11|[Results of `std::source_location`](reference/source_location.md)| For implementation specific `std::source_location` results| +|9|[Benchmarks](#9-benchmarks)| Benchmarking | +|10|[Compilers](#10-compiler-support)| Supported compilers| +|11|[Compiler issues](#11-compiler-issues)| Workarounds for various compiler issues| +|12|[Results of `std::source_location`](reference/source_location.md)| For implementation specific `std::source_location` results| > [!TIP] > Use the built-in [table of contents](https://github.blog/changelog/2021-04-13-table-of-contents-support-in-markdown-files/) to navigate this guide. > Even better in [full read view](./README.md) of this page. @@ -86,7 +87,7 @@ unlocked the potential of [`constexpr` algorithms](https://www.open-std.org/jtc1 - ***Easy to Use***: Class-based approach with intuitive syntax - ***Convenient***: `enum_bitset` provides an enhanced enum aware `std::bitset` (see 3 above) - ***Useful***: `conjure_type` gives you the type string of _any type!_ (see 4 above) -- ***Wide Compiler Compatibility***: Support for: (see 7 above) +- ***Wide Compiler Compatibility***: Support for: (see 10 above) - GCC - Clang - MSVC @@ -99,7 +100,7 @@ unlocked the potential of [`constexpr` algorithms](https://www.open-std.org/jtc1 - `for_each_n` - `dispatch` - iterators and more! -- ***Transparency***: Compiler implementation variability fully documented, verifiable and reportable (see 9 above) +- ***Transparency***: Compiler implementation variability fully documented, verifiable and reportable (see 12 above) --- # 3. API and Examples using `conjure_enum` @@ -1830,7 +1831,22 @@ Compilation (2 times):

--- -# 9. Compiler support +# 9. Benchmarks +We have benchmarked `conjure_enum` and `magic_enum`. The results are shown below. For `magic_enum` we created a separate repo (see [here](https://github.com/fix8mt/magic_enum_benchmark). +We ran each benchmark 3 times, and averaged the results. +| Compiler | `conjure_enum` | `magic_enum` | Notes | +| :--- | :--- | :--- | +| MSVC | 0.441 | 0.385 | using cl from command prompt +| clang | 0.4 | 0.4 | using ClangBuildAnalyzer + +Notes +- MSVC: Windows 11 ThinkCentre 16x 13th Gen Intel i7-13700, 32Gb; MSVC 2022 / 17.11.0. +- Clang: Ubuntu 24.04 12th Gen Intel i9-12900T, 32Gb; Clang 18.1.3 +- `magic_enum`: single header only +- `conjure_enum`: minimal build + +--- +# 10. Compiler support | Compiler | Version(s) | Notes | Unsupported | | :--- | :--- | :--- | ---: | | [gcc](https://gcc.gnu.org/projects/cxx-status.html) | `11`, `12`, `13`, `14`| `std::format` not complete in `11`, `12` | `<= 10` | @@ -1838,7 +1854,7 @@ Compilation (2 times): | [msvc](https://learn.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance) | `16`, `17` | Visual Studio 2019,2022, latest `17.11.0`| `<= 16.9`| | [xcode](https://developer.apple.com/support/xcode/) | `15` | Apple LLVM 15.0.0, some issues with `constexpr`, workarounds| `<= 14`| -# 10. Compiler issues +# 11. Compiler issues | Compiler | Version(s) | Issues | Workaround | | :--- | :--- | :--- | ---: | | clang | `16`, `17`, `18`| Compiler reports integers outside valid range [x,y]| specify underlying type when declaring enum eg. `enum class foo : int` | From 07d9167136a646aa833934d86d199745c8999b8a Mon Sep 17 00:00:00 2001 From: David Dight Date: Sat, 17 Aug 2024 07:45:15 +1000 Subject: [PATCH 112/235] updated --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6795492..7d9493c 100644 --- a/README.md +++ b/README.md @@ -1835,9 +1835,9 @@ Compilation (2 times): We have benchmarked `conjure_enum` and `magic_enum`. The results are shown below. For `magic_enum` we created a separate repo (see [here](https://github.com/fix8mt/magic_enum_benchmark). We ran each benchmark 3 times, and averaged the results. | Compiler | `conjure_enum` | `magic_enum` | Notes | -| :--- | :--- | :--- | -| MSVC | 0.441 | 0.385 | using cl from command prompt -| clang | 0.4 | 0.4 | using ClangBuildAnalyzer +| :--- | :--- | :--- |:--- | +| MSVC | 0.441 | 0.385 | using cl from command prompt| +| clang | 0.4 | 0.4 | using ClangBuildAnalyzer| Notes - MSVC: Windows 11 ThinkCentre 16x 13th Gen Intel i7-13700, 32Gb; MSVC 2022 / 17.11.0. From 2f50071e34e272e181b936c2476d287f6dfa5c50 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sat, 17 Aug 2024 07:50:50 +1000 Subject: [PATCH 113/235] updated --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7d9493c..be2a58f 100644 --- a/README.md +++ b/README.md @@ -1832,14 +1832,15 @@ Compilation (2 times): --- # 9. Benchmarks -We have benchmarked `conjure_enum` and `magic_enum`. The results are shown below. For `magic_enum` we created a separate repo (see [here](https://github.com/fix8mt/magic_enum_benchmark). +We have benchmarked `conjure_enum` and `magic_enum`. The results are shown below. For `magic_enum` we created a separate repo (see [here](https://github.com/fix8mt/magic_enum_benchmark)). We ran each benchmark 3 times, and averaged the results. -| Compiler | `conjure_enum` | `magic_enum` | Notes | +| Compiler | `conjure_enum` (secs) | `magic_enum` (secs)| Notes | | :--- | :--- | :--- |:--- | | MSVC | 0.441 | 0.385 | using cl from command prompt| | clang | 0.4 | 0.4 | using ClangBuildAnalyzer| Notes +- Both benchmarks are using [cbenchmark.sh](examples/cbenchmark.sh) and [cbenchmark.cpp](examples/cbenchmark.cpp) - MSVC: Windows 11 ThinkCentre 16x 13th Gen Intel i7-13700, 32Gb; MSVC 2022 / 17.11.0. - Clang: Ubuntu 24.04 12th Gen Intel i9-12900T, 32Gb; Clang 18.1.3 - `magic_enum`: single header only From 6b40661f6e6bb820e378e307a5b3d9d98de19480 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sat, 17 Aug 2024 07:57:00 +1000 Subject: [PATCH 114/235] updated --- README.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index be2a58f..a469dd2 100644 --- a/README.md +++ b/README.md @@ -1832,20 +1832,26 @@ Compilation (2 times): --- # 9. Benchmarks -We have benchmarked `conjure_enum` and `magic_enum`. The results are shown below. For `magic_enum` we created a separate repo (see [here](https://github.com/fix8mt/magic_enum_benchmark)). -We ran each benchmark 3 times, and averaged the results. +We have benchmarked compilation times for `conjure_enum` and `magic_enum`. +For `magic_enum` we created a separate repo (see [here](https://github.com/fix8mt/magic_enum_benchmark)). + | Compiler | `conjure_enum` (secs) | `magic_enum` (secs)| Notes | | :--- | :--- | :--- |:--- | | MSVC | 0.441 | 0.385 | using cl from command prompt| | clang | 0.4 | 0.4 | using ClangBuildAnalyzer| -Notes +## Notes +- Benchmark run 10 times, best result shown - Both benchmarks are using [cbenchmark.sh](examples/cbenchmark.sh) and [cbenchmark.cpp](examples/cbenchmark.cpp) - MSVC: Windows 11 ThinkCentre 16x 13th Gen Intel i7-13700, 32Gb; MSVC 2022 / 17.11.0. - Clang: Ubuntu 24.04 12th Gen Intel i9-12900T, 32Gb; Clang 18.1.3 - `magic_enum`: single header only - `conjure_enum`: minimal build +## Discussion +For MSVC, `magic_enum` compilation times a slighly better than `conjure_enum` (around %10). For clang the results are identical. +From a compilation performance perspective, `conjure_enum` at least matches the performance of `magic_enum`. + --- # 10. Compiler support | Compiler | Version(s) | Notes | Unsupported | From a32371a2e3439f4718f59eda4ec28b42e027211a Mon Sep 17 00:00:00 2001 From: David Dight Date: Sat, 17 Aug 2024 07:59:57 +1000 Subject: [PATCH 115/235] updated --- README.md | 85 +++++++++++++++++++++++++++---------------------------- 1 file changed, 41 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index a469dd2..ace3291 100644 --- a/README.md +++ b/README.md @@ -1740,89 +1740,86 @@ Processing all files and saving to 'cbenchmark.dat'... Analyzing build trace from 'cbenchmark.dat'... **** Time summary: Compilation (2 times): - Parsing (frontend): 0.7 s + Parsing (frontend): 0.4 s Codegen & opts (backend): 0.0 s **** Files that took longest to parse (compiler frontend): - 662 ms: build_clang/CMakeFiles/cbenchmark.dir/examples/cbenchmark.cpp.o - -**** Files that took longest to codegen (compiler backend): - 18 ms: build_clang/CMakeFiles/cbenchmark.dir/examples/cbenchmark.cpp.o + 423 ms: build_clang/CMakeFiles/cbenchmark.dir/examples/cbenchmark.cpp.o **** Templates that took longest to instantiate: - 290 ms: FIX8::conjure_enum (1 times, avg 290 ms) - 140 ms: FIX8::conjure_enum::_entries<0UL, 1UL, 2UL, 3UL, 4UL, 5UL... (1 times, avg 140 ms) - 82 ms: FIX8::conjure_enum::_values<0UL, 1UL, 2UL, 3UL, 4UL, 5UL,... (1 times, avg 82 ms) + 187 ms: FIX8::conjure_enum (1 times, avg 187 ms) + 119 ms: FIX8::conjure_enum::_entries<0UL, 1UL, 2UL, 3UL, 4UL, 5UL... (1 times, avg 119 ms) 8 ms: FIX8::conjure_enum::_sorted_entries (1 times, avg 8 ms) - 7 ms: std::reverse_iterator (1 times, avg 7 ms) 6 ms: std::sort> *, boo... (1 times, avg 6 ms) 6 ms: std::__sort> *, _... (1 times, avg 6 ms) - 6 ms: std::reverse_iterator (1 times, avg 6 ms) - 5 ms: std::unordered_map (1 times, avg 5 ms) 5 ms: std::__introsort_loop>, 47> (1 times, avg 3 ms) - 3 ms: std::_Hashtable, std::allocator::enum_to_string (1 times, avg 3 ms) - 3 ms: std::tuple, char, std::basic_string_vie... (1 times, avg 3 ms) + 3 ms: std::array>, 72> (1 times, avg 3 ms) + 2 ms: std::tuple, char, std::basic_string_vie... (1 times, avg 2 ms) 2 ms: std::__unguarded_partition_pivot> (1 times, avg 2 ms) - 2 ms: std::tuple>::tuple::_enum_name> *... (1 times, avg 2 ms) 2 ms: std::__partial_sort::_enum_name> (1 times, avg 2 ms) 2 ms: std::__heap_select, char, std::basic_string_vie... (1 times, avg 2 ms) - 2 ms: FIX8::conjure_enum::_enum_name::_enum_name::_enum_name::_enum_name::_enum_name>... (1 times, avg 2 ms) + 1 ms: std::optional (1 times, avg 1 ms) + 1 ms: std::to_array, char, std::ba... (1 times, avg 1 ms) + 1 ms: std::basic_string (1 times, avg 1 ms) + 1 ms: std::basic_string (1 times, avg 1 ms) + 1 ms: std::__adjust_heap (1 times, avg 1 ms) + 1 ms: std::basic_string (1 times, avg 1 ms) + 1 ms: std::basic_string (1 times, avg 1 ms) + 1 ms: std::__and_, std::__is_swappable, char, std::basic_s... (1 times, avg 1 ms) + 1 ms: std::__final_insertion_sort::_M_construct (1 times, avg 1 ms) + 1 ms: std::basic_string::_M_construct (1 times, avg 1 ms) + 1 ms: std::basic_string::_M_construct (1 times, avg 1 ms) + 1 ms: std::operator+, std::allocator> (1 times, avg 1 ms) **** Template sets that took longest to instantiate: - 290 ms: FIX8::conjure_enum<$> (1 times, avg 290 ms) - 140 ms: FIX8::conjure_enum<$>::_entries<$> (1 times, avg 140 ms) - 82 ms: FIX8::conjure_enum<$>::_values<$> (1 times, avg 82 ms) - 78 ms: FIX8::conjure_enum<$>::_enum_name<$> (47 times, avg 1 ms) - 55 ms: FIX8::conjure_enum<$>::_is_valid<$> (72 times, avg 0 ms) - 38 ms: FIX8::conjure_enum<$>::_get_name<$> (47 times, avg 0 ms) - 15 ms: std::tuple<$>::tuple<$> (20 times, avg 0 ms) - 13 ms: std::reverse_iterator<$> (2 times, avg 6 ms) + 187 ms: FIX8::conjure_enum<$> (1 times, avg 187 ms) + 119 ms: FIX8::conjure_enum<$>::_entries<$> (1 times, avg 119 ms) + 49 ms: FIX8::conjure_enum<$>::_get_name<$> (72 times, avg 0 ms) + 12 ms: std::tuple<$>::tuple<$> (21 times, avg 0 ms) 8 ms: FIX8::conjure_enum<$>::_sorted_entries (1 times, avg 8 ms) 7 ms: std::basic_string<$> (5 times, avg 1 ms) 6 ms: std::sort<$> (1 times, avg 6 ms) 6 ms: std::__sort<$> (1 times, avg 6 ms) + 5 ms: std::basic_string<$>::_M_construct<$> (5 times, avg 1 ms) 5 ms: std::tuple<$> (2 times, avg 2 ms) - 5 ms: std::_Hashtable<$> (2 times, avg 2 ms) - 5 ms: std::unordered_map<$> (1 times, avg 5 ms) 5 ms: std::__introsort_loop<$> (1 times, avg 5 ms) 4 ms: std::array<$> (2 times, avg 2 ms) - 4 ms: std::basic_string<$>::_M_construct<$> (4 times, avg 1 ms) - 3 ms: FIX8::conjure_enum<$>::enum_to_string (1 times, avg 3 ms) - 3 ms: std::__and_<$> (4 times, avg 0 ms) 2 ms: std::__unguarded_partition_pivot<$> (1 times, avg 2 ms) + 2 ms: std::__and_<$> (3 times, avg 0 ms) 2 ms: std::__move_median_to_first<$> (1 times, avg 2 ms) 2 ms: std::iter_swap<$> (1 times, avg 2 ms) 2 ms: std::__partial_sort<$> (1 times, avg 2 ms) - 2 ms: std::copy<$> (3 times, avg 0 ms) 2 ms: std::__heap_select<$> (1 times, avg 2 ms) - 2 ms: std::_Tuple_impl<$> (2 times, avg 1 ms) 2 ms: std::__make_heap<$> (1 times, avg 2 ms) + 1 ms: std::_Tuple_impl<$> (2 times, avg 0 ms) 1 ms: std::optional<$> (1 times, avg 1 ms) 1 ms: std::to_array<$> (1 times, avg 1 ms) + 1 ms: std::__adjust_heap<$> (1 times, avg 1 ms) + 1 ms: std::basic_string<$>::basic_string (2 times, avg 0 ms) + 1 ms: std::__final_insertion_sort<$> (1 times, avg 1 ms) + 1 ms: std::operator+, std::allocator> (1 times, avg 1 ms) + 1 ms: std::__insertion_sort<$> (1 times, avg 1 ms) + 0 ms: FIX8::conjure_enum<$>::_tuple_comp_rev (1 times, avg 0 ms) + 0 ms: std::tuple>::operator= (1 times, avg 0 ms) + 0 ms: __gnu_cxx::__to_xstring<$> (1 times, avg 0 ms) **** Functions that took longest to compile: - 2 ms: test_conjure_enum(std::errc) (/home/davidd/prog/conjure_enum_tclass/examples/cbenchmark.cpp) + 0 ms: test_conjure_enum(std::errc) (/home/davidd/prog/conjure_enum_tclass/examples/cbenchmark.cpp) **** Function sets that took longest to compile / optimize: **** Expensive headers: -181 ms: /home/davidd/prog/conjure_enum_tclass/include/fix8/conjure_enum.hpp (included 1 times, avg 181 ms), included via: +166 ms: /usr/include/c++/14/system_error (included 1 times, avg 166 ms), included via: 1x: -173 ms: /usr/include/c++/14/system_error (included 1 times, avg 173 ms), included via: +54 ms: /home/davidd/prog/conjure_enum_tclass/include/fix8/conjure_enum.hpp (included 1 times, avg 54 ms), included via: 1x: done in 0.0s. @@ -1850,7 +1847,7 @@ For `magic_enum` we created a separate repo (see [here](https://github.com/fix8m ## Discussion For MSVC, `magic_enum` compilation times a slighly better than `conjure_enum` (around %10). For clang the results are identical. -From a compilation performance perspective, `conjure_enum` at least matches the performance of `magic_enum`. +From a compilation performance perspective, `conjure_enum` roughly matches the performance of `magic_enum`. --- # 10. Compiler support From f65ec38476ee58aca3888e61418dbbeff5ffb743 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sat, 17 Aug 2024 08:01:54 +1000 Subject: [PATCH 116/235] pre-rel 1.1.0a --- include/fix8/conjure_enum.hpp | 4 ++-- include/fix8/conjure_enum_bitset.hpp | 6 ++++-- utests/unittests.cpp | 8 ++++---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index de08b1f..5f77167 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -414,8 +414,8 @@ class conjure_enum final : public static_only static constexpr int get_enum_max_value() noexcept { return enum_max_value; } static constexpr auto min_v { values.front() }; static constexpr auto max_v { values.back() }; - static constexpr int get_enum_min_actual_value() noexcept { return static_cast(min_v); } - static constexpr int get_enum_max_actual_value() noexcept { return static_cast(max_v); } + static constexpr int get_actual_enum_min_value() noexcept { return static_cast(min_v); } + static constexpr int get_actual_enum_max_value() noexcept { return static_cast(max_v); } #if not defined FIX8_CONJURE_ENUM_MINIMAL #include diff --git a/include/fix8/conjure_enum_bitset.hpp b/include/fix8/conjure_enum_bitset.hpp index 6415803..0dc9db3 100644 --- a/include/fix8/conjure_enum_bitset.hpp +++ b/include/fix8/conjure_enum_bitset.hpp @@ -48,12 +48,14 @@ namespace FIX8 { template concept valid_bitset_enum = valid_enum and requires(T) { - requires static_cast(conjure_enum::values.back()) < conjure_enum::count(); + requires conjure_enum::is_continuous(); + requires conjure_enum::get_actual_enum_min_value() == 0; + requires conjure_enum::get_actual_enum_max_value() < conjure_enum::count(); }; //----------------------------------------------------------------------------------------- // bitset based on supplied enum -// Note: your enum sequence must be continuous with the last enum value < count of enumerations +// Note: your enum sequence must be 0 based, continuous and the last enum value < count of enumerations //----------------------------------------------------------------------------------------- template class enum_bitset diff --git a/utests/unittests.cpp b/utests/unittests.cpp index b78a245..8d5defb 100644 --- a/utests/unittests.cpp +++ b/utests/unittests.cpp @@ -73,8 +73,8 @@ TEST_CASE("default range") { REQUIRE(conjure_enum::get_enum_min_value() == FIX8_CONJURE_ENUM_MIN_VALUE); REQUIRE(conjure_enum::get_enum_max_value() == FIX8_CONJURE_ENUM_MAX_VALUE); - REQUIRE(conjure_enum::get_enum_min_actual_value() == 0); - REQUIRE(conjure_enum::get_enum_max_actual_value() == 14); + REQUIRE(conjure_enum::get_actual_enum_min_value() == 0); + REQUIRE(conjure_enum::get_actual_enum_max_value() == 14); } //----------------------------------------------------------------------------------------- @@ -90,8 +90,8 @@ TEST_CASE("custom range") { REQUIRE(conjure_enum::get_enum_min_value() == 0); REQUIRE(conjure_enum::get_enum_max_value() == 7); - REQUIRE(conjure_enum::get_enum_min_value() == conjure_enum::get_enum_min_actual_value()); - REQUIRE(conjure_enum::get_enum_max_value() == conjure_enum::get_enum_max_actual_value()); + REQUIRE(conjure_enum::get_enum_min_value() == conjure_enum::get_actual_enum_min_value()); + REQUIRE(conjure_enum::get_enum_max_value() == conjure_enum::get_actual_enum_max_value()); REQUIRE(conjure_enum::get_enum_min_value() == 0); REQUIRE(conjure_enum::get_enum_max_value() == 7); REQUIRE(conjure_enum::get_enum_min_value() == 0); From 06b44c7d41e8a1f2e6d0d3aa271ccbd14c27e593 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sat, 17 Aug 2024 11:13:38 +1000 Subject: [PATCH 117/235] updated --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index ace3291..c799edb 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,8 @@ enum class numbers { zero, one, two, three, four, five, six, seven, eight, nine ## a) `enum_to_string` ```c++ static constexpr std::string_view enum_to_string(T value, bool noscope=false); +template +static constexpr std::string_view enum_to_string(); ``` Returns a `std::string_view` or empty if not found. Optionally passing `true` will remove scope in result if present. `noscope` option ![](assets/notminimalred.svg). @@ -123,6 +125,7 @@ auto name_trim { conjure_enum::enum_to_string(component::path, true) auto alias_name { conjure_enum::enum_to_string(component::test) }; // alias auto noscope_name { conjure_enum::enum_to_string(path) }; std::cout << name << '\n' << name_trim << '\n' << alias_name << '\n' << noscope_name << '\n'; +std::cout << conjure_enum::enum_to_string() << '\n'; ``` _output_ ```CSV @@ -130,6 +133,7 @@ component::path path component::path path +numbers::two ``` ### Aliases Because all methods in `conjure_enum` are defined _within_ a `class` instead of individual template functions in a `namespace`, you can reduce your From 7ab4689aeda2241c911aee267e751d055adbee84 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sat, 17 Aug 2024 11:21:49 +1000 Subject: [PATCH 118/235] updated --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c799edb..ea76f08 100644 --- a/README.md +++ b/README.md @@ -1838,8 +1838,10 @@ For `magic_enum` we created a separate repo (see [here](https://github.com/fix8m | Compiler | `conjure_enum` (secs) | `magic_enum` (secs)| Notes | | :--- | :--- | :--- |:--- | -| MSVC | 0.441 | 0.385 | using cl from command prompt| +| MSVC | 0.441 | 0.385 | using cl from command prompt, `cl /nologo /MD /std:c++latest /Bt+ -I build\_deps\magic_enum-src\include cbenchmark.cpp|find "c1xx.dll"`| +| | | `cl /nologo /MD /std:c++latest /Bt+ -I build\_deps\magic_enum-src\include cbenchmark.cpp|find "c1xx.dll"`| | clang | 0.4 | 0.4 | using ClangBuildAnalyzer| +||cl /nologo /MD /std:c++latest /Bt+ /I ..\include ..\examples\cbenchmark.cpp|find "c1xx.dll"|| ## Notes - Benchmark run 10 times, best result shown From c6a266c18328f3a1c11e402aea5b8e35a135e6de Mon Sep 17 00:00:00 2001 From: David Dight Date: Sat, 17 Aug 2024 11:23:35 +1000 Subject: [PATCH 119/235] updated --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ea76f08..b60b99c 100644 --- a/README.md +++ b/README.md @@ -1839,9 +1839,9 @@ For `magic_enum` we created a separate repo (see [here](https://github.com/fix8m | Compiler | `conjure_enum` (secs) | `magic_enum` (secs)| Notes | | :--- | :--- | :--- |:--- | | MSVC | 0.441 | 0.385 | using cl from command prompt, `cl /nologo /MD /std:c++latest /Bt+ -I build\_deps\magic_enum-src\include cbenchmark.cpp|find "c1xx.dll"`| -| | | `cl /nologo /MD /std:c++latest /Bt+ -I build\_deps\magic_enum-src\include cbenchmark.cpp|find "c1xx.dll"`| +| | cl /nologo /MD /std:c++latest /Bt+ /I ..\include ..\examples\cbenchmark.cpp|find "c1xx.dll" | `cl /nologo /MD /std:c++latest /Bt+ -I build\_deps\magic_enum-src\include cbenchmark.cpp|find "c1xx.dll"`| | clang | 0.4 | 0.4 | using ClangBuildAnalyzer| -||cl /nologo /MD /std:c++latest /Bt+ /I ..\include ..\examples\cbenchmark.cpp|find "c1xx.dll"|| +||`ClangBuildAnalyzerLoc=~/prog/ClangBuildAnalyzer/build ArtifactLoc=build_clang examples/cbenchmark.sh`|`ClangBuildAnalyzerLoc=~/prog/ClangBuildAnalyzer/build ArtifactLoc=build_clang ./cbenchmark.sh`| ## Notes - Benchmark run 10 times, best result shown From a16b69da9008b1e78f134d8cd7ff806ffefcfb60 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sat, 17 Aug 2024 11:25:12 +1000 Subject: [PATCH 120/235] updated --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b60b99c..10a6382 100644 --- a/README.md +++ b/README.md @@ -1838,8 +1838,8 @@ For `magic_enum` we created a separate repo (see [here](https://github.com/fix8m | Compiler | `conjure_enum` (secs) | `magic_enum` (secs)| Notes | | :--- | :--- | :--- |:--- | -| MSVC | 0.441 | 0.385 | using cl from command prompt, `cl /nologo /MD /std:c++latest /Bt+ -I build\_deps\magic_enum-src\include cbenchmark.cpp|find "c1xx.dll"`| -| | cl /nologo /MD /std:c++latest /Bt+ /I ..\include ..\examples\cbenchmark.cpp|find "c1xx.dll" | `cl /nologo /MD /std:c++latest /Bt+ -I build\_deps\magic_enum-src\include cbenchmark.cpp|find "c1xx.dll"`| +| MSVC | 0.441 | 0.385 | using cl from command prompt| +| | `cl /nologo /MD /std:c++latest /Bt+ /I ..\include ..\examples\cbenchmark.cpp|find "c1xx.dll"` | `cl /nologo /MD /std:c++latest /Bt+ -I build\_deps\magic_enum-src\include cbenchmark.cpp|find "c1xx.dll"`| | clang | 0.4 | 0.4 | using ClangBuildAnalyzer| ||`ClangBuildAnalyzerLoc=~/prog/ClangBuildAnalyzer/build ArtifactLoc=build_clang examples/cbenchmark.sh`|`ClangBuildAnalyzerLoc=~/prog/ClangBuildAnalyzer/build ArtifactLoc=build_clang ./cbenchmark.sh`| From 933aad264fafd49b2acbea56474fc7de5beabb1c Mon Sep 17 00:00:00 2001 From: David Dight Date: Sat, 17 Aug 2024 11:25:54 +1000 Subject: [PATCH 121/235] updated --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 10a6382..a3e8bf9 100644 --- a/README.md +++ b/README.md @@ -1839,9 +1839,9 @@ For `magic_enum` we created a separate repo (see [here](https://github.com/fix8m | Compiler | `conjure_enum` (secs) | `magic_enum` (secs)| Notes | | :--- | :--- | :--- |:--- | | MSVC | 0.441 | 0.385 | using cl from command prompt| -| | `cl /nologo /MD /std:c++latest /Bt+ /I ..\include ..\examples\cbenchmark.cpp|find "c1xx.dll"` | `cl /nologo /MD /std:c++latest /Bt+ -I build\_deps\magic_enum-src\include cbenchmark.cpp|find "c1xx.dll"`| +| | `cl /nologo /MD /std:c++latest /Bt+ /I ..\include ..\examples\cbenchmark.cpp|find "c1xx.dll"` | `cl /nologo /MD /std:c++latest /Bt+ -I build\_deps\magic_enum-src\include cbenchmark.cpp|find "c1xx.dll"`|| | clang | 0.4 | 0.4 | using ClangBuildAnalyzer| -||`ClangBuildAnalyzerLoc=~/prog/ClangBuildAnalyzer/build ArtifactLoc=build_clang examples/cbenchmark.sh`|`ClangBuildAnalyzerLoc=~/prog/ClangBuildAnalyzer/build ArtifactLoc=build_clang ./cbenchmark.sh`| +||`ClangBuildAnalyzerLoc=~/prog/ClangBuildAnalyzer/build ArtifactLoc=build_clang examples/cbenchmark.sh`|`ClangBuildAnalyzerLoc=~/prog/ClangBuildAnalyzer/build ArtifactLoc=build_clang ./cbenchmark.sh`|| ## Notes - Benchmark run 10 times, best result shown From 7073e087e52857c7be2af85f27b7a4f8594f7be9 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sat, 17 Aug 2024 11:26:56 +1000 Subject: [PATCH 122/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a3e8bf9..d3a7a88 100644 --- a/README.md +++ b/README.md @@ -1839,7 +1839,7 @@ For `magic_enum` we created a separate repo (see [here](https://github.com/fix8m | Compiler | `conjure_enum` (secs) | `magic_enum` (secs)| Notes | | :--- | :--- | :--- |:--- | | MSVC | 0.441 | 0.385 | using cl from command prompt| -| | `cl /nologo /MD /std:c++latest /Bt+ /I ..\include ..\examples\cbenchmark.cpp|find "c1xx.dll"` | `cl /nologo /MD /std:c++latest /Bt+ -I build\_deps\magic_enum-src\include cbenchmark.cpp|find "c1xx.dll"`|| +| | `cl /nologo /MD /std:c++latest /Bt+ /I ..\include ..\examples\cbenchmark.cpp\|find "c1xx.dll"` | `cl /nologo /MD /std:c++latest /Bt+ -I build\_deps\magic_enum-src\include cbenchmark.cpp\|find "c1xx.dll"`|| | clang | 0.4 | 0.4 | using ClangBuildAnalyzer| ||`ClangBuildAnalyzerLoc=~/prog/ClangBuildAnalyzer/build ArtifactLoc=build_clang examples/cbenchmark.sh`|`ClangBuildAnalyzerLoc=~/prog/ClangBuildAnalyzer/build ArtifactLoc=build_clang ./cbenchmark.sh`|| From fe7eb9167b9084f038bde961fbbded03a3efda43 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sat, 17 Aug 2024 11:28:00 +1000 Subject: [PATCH 123/235] updated --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d3a7a88..1ce6436 100644 --- a/README.md +++ b/README.md @@ -1839,9 +1839,9 @@ For `magic_enum` we created a separate repo (see [here](https://github.com/fix8m | Compiler | `conjure_enum` (secs) | `magic_enum` (secs)| Notes | | :--- | :--- | :--- |:--- | | MSVC | 0.441 | 0.385 | using cl from command prompt| -| | `cl /nologo /MD /std:c++latest /Bt+ /I ..\include ..\examples\cbenchmark.cpp\|find "c1xx.dll"` | `cl /nologo /MD /std:c++latest /Bt+ -I build\_deps\magic_enum-src\include cbenchmark.cpp\|find "c1xx.dll"`|| +|_command_ | `cl /nologo /MD /std:c++latest /Bt+ /I ..\include ..\examples\cbenchmark.cpp\|find "c1xx.dll"` | `cl /nologo /MD /std:c++latest /Bt+ -I build\_deps\magic_enum-src\include cbenchmark.cpp\|find "c1xx.dll"`|| | clang | 0.4 | 0.4 | using ClangBuildAnalyzer| -||`ClangBuildAnalyzerLoc=~/prog/ClangBuildAnalyzer/build ArtifactLoc=build_clang examples/cbenchmark.sh`|`ClangBuildAnalyzerLoc=~/prog/ClangBuildAnalyzer/build ArtifactLoc=build_clang ./cbenchmark.sh`|| +|_command_|`ClangBuildAnalyzerLoc=~/prog/ClangBuildAnalyzer/build ArtifactLoc=build_clang examples/cbenchmark.sh`|`ClangBuildAnalyzerLoc=~/prog/ClangBuildAnalyzer/build ArtifactLoc=build_clang ./cbenchmark.sh`|| ## Notes - Benchmark run 10 times, best result shown From f899e58f75f10df1ce8d789aa483c73827aed90f Mon Sep 17 00:00:00 2001 From: David Dight Date: Sat, 17 Aug 2024 12:04:46 +1000 Subject: [PATCH 124/235] pre-rel 1.1.0a --- utests/unittests.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/utests/unittests.cpp b/utests/unittests.cpp index 8d5defb..8214709 100644 --- a/utests/unittests.cpp +++ b/utests/unittests.cpp @@ -254,6 +254,8 @@ TEST_CASE("enum_to_string") REQUIRE(conjure_enum::enum_to_string(static_cast(100)).empty()); REQUIRE(conjure_enum::enum_to_string() == "component::fragment"); REQUIRE(conjure_enum::enum_to_string() == "fragment"); + using enum numbers; + REQUIRE(conjure_enum::enum_to_string() == "numbers::two"); } //----------------------------------------------------------------------------------------- From f652bd9e8fca1a336b84125cda41ef138b160735 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sun, 18 Aug 2024 07:22:18 +1000 Subject: [PATCH 125/235] updated --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1ce6436..882a207 100644 --- a/README.md +++ b/README.md @@ -1841,7 +1841,9 @@ For `magic_enum` we created a separate repo (see [here](https://github.com/fix8m | MSVC | 0.441 | 0.385 | using cl from command prompt| |_command_ | `cl /nologo /MD /std:c++latest /Bt+ /I ..\include ..\examples\cbenchmark.cpp\|find "c1xx.dll"` | `cl /nologo /MD /std:c++latest /Bt+ -I build\_deps\magic_enum-src\include cbenchmark.cpp\|find "c1xx.dll"`|| | clang | 0.4 | 0.4 | using ClangBuildAnalyzer| -|_command_|`ClangBuildAnalyzerLoc=~/prog/ClangBuildAnalyzer/build ArtifactLoc=build_clang examples/cbenchmark.sh`|`ClangBuildAnalyzerLoc=~/prog/ClangBuildAnalyzer/build ArtifactLoc=build_clang ./cbenchmark.sh`|| +|_command_|`make` +`ClangBuildAnalyzerLoc=~/prog/ClangBuildAnalyzer/build ArtifactLoc=build_clang examples/cbenchmark.sh`|`make` +`ClangBuildAnalyzerLoc=~/prog/ClangBuildAnalyzer/build ArtifactLoc=build_clang ./cbenchmark.sh`|| ## Notes - Benchmark run 10 times, best result shown From 24aa4e3e7afec8cd19909d5caa01ef93416c2c57 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sun, 18 Aug 2024 07:22:58 +1000 Subject: [PATCH 126/235] updated --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 882a207..ef77857 100644 --- a/README.md +++ b/README.md @@ -1841,9 +1841,7 @@ For `magic_enum` we created a separate repo (see [here](https://github.com/fix8m | MSVC | 0.441 | 0.385 | using cl from command prompt| |_command_ | `cl /nologo /MD /std:c++latest /Bt+ /I ..\include ..\examples\cbenchmark.cpp\|find "c1xx.dll"` | `cl /nologo /MD /std:c++latest /Bt+ -I build\_deps\magic_enum-src\include cbenchmark.cpp\|find "c1xx.dll"`|| | clang | 0.4 | 0.4 | using ClangBuildAnalyzer| -|_command_|`make` -`ClangBuildAnalyzerLoc=~/prog/ClangBuildAnalyzer/build ArtifactLoc=build_clang examples/cbenchmark.sh`|`make` -`ClangBuildAnalyzerLoc=~/prog/ClangBuildAnalyzer/build ArtifactLoc=build_clang ./cbenchmark.sh`|| +|_command_|`make`; `ClangBuildAnalyzerLoc=~/prog/ClangBuildAnalyzer/build ArtifactLoc=build_clang examples/cbenchmark.sh`|`make`; `ClangBuildAnalyzerLoc=~/prog/ClangBuildAnalyzer/build ArtifactLoc=build_clang ./cbenchmark.sh`|| ## Notes - Benchmark run 10 times, best result shown From e1ce7b7d0dd1067f2de24072caa5bcbe99a09866 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sun, 18 Aug 2024 08:18:08 +1000 Subject: [PATCH 127/235] updated --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ef77857..c3e273d 100644 --- a/README.md +++ b/README.md @@ -195,23 +195,26 @@ _output_ 12 100 <-- invalid, error value ``` -## d) `int_to_enum` +## d) `int_to_enum`, `enum_cast` ```c++ static constexpr std::optional int_to_enum(int value); +static constexpr T enum_cast(int value); ``` Returns a `std::optional`. Empty if value was not valid. Use `std::optional::value_or()` to set an error value -and avoid throwing an exception. +and avoid throwing an exception. `enum_cast` will cast to the enum type regardless of whether the value is a valid enum. ```c++ int value { static_cast(conjure_enum::int_to_enum(12).value()) }; int noscope_value { static_cast(conjure_enum::int_to_enum(12).value()) }; int bad_value { static_cast(conjure_enum::int_to_enum(100).value_or(component(100))) }; std::cout << value << '\n' << noscope_value << '\n' << bad_value << '\n'; +std::cout << static_cast(conjure_enum::enum_cast(150)) << '\n'; ``` _output_ ```CSV 12 12 100 <-- invalid, error value +150 <-- invalid, but still casted ``` ## e) `enum_to_int`, `enum_to_underlying` ```c++ From 87e8087784f782dae0c6a00e491df679066e98af Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 21 Aug 2024 05:38:56 +1000 Subject: [PATCH 128/235] updated --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index c3e273d..eb3fe2f 100644 --- a/README.md +++ b/README.md @@ -896,6 +896,7 @@ for the bit positions (and names). > - Your enum sequence _must_ be 0 based > - Continuous > - The last value must be less than the count of enumerations +> - This implementation is limited to 64 bits > > We decided on this restriction for both simplicity and practicality - bitsets only really make sense when represented in this manner. From d2cbc3daf4b92823fb40426377951c54507a9c4a Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 21 Aug 2024 06:27:01 +1000 Subject: [PATCH 129/235] updated --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index eb3fe2f..003e148 100644 --- a/README.md +++ b/README.md @@ -70,12 +70,10 @@ Based on the awesome work in [`magic_enum`](https://github.com/Neargye/magic_enu this library offers a streamlined and powerful way to add reflection capabilities to your C++ enums and other types. We've optimized the core functionality, focusing on the main features developers usually want. We've also added general purpose typename reflection for any type. -## b) Embracing C++20 - `conjure_enum`[^1] takes full advantage of recently added C++20 features. We've leveraged the convenience of [`std::source_location`](https://en.cppreference.com/w/cpp/utility/source_location) and unlocked the potential of [`constexpr` algorithms](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0202r3.html) and [concepts](https://en.cppreference.com/w/cpp/language/constraints). -## c) Highlights +## b) Highlights - ***Single Header-Only***: No external dependencies, simplifying integration into your project - ***Modern C++20***: Entirely `constexpr` for compile-time safety, efficiency and performance; no macros @@ -92,7 +90,7 @@ unlocked the potential of [`constexpr` algorithms](https://www.open-std.org/jtc1 - Clang - MSVC - XCode/Apple Clang -- ***Confidence in Quality***: Includes comprehensive unit test suite for reliable functionality and profiling +- ***Confidence***: Includes comprehensive unit test suite for reliable functionality and profiling - ***Expanded***: Enhanced API: - `add_scope` - `remove_scope` From 51a32f57ab87c42da93c526830c107d0cb2366c3 Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 21 Aug 2024 06:27:22 +1000 Subject: [PATCH 130/235] pre-rel 1.1b --- examples/cbenchmark.cpp | 23 +++++++++++++++++++---- include/fix8/conjure_enum.hpp | 6 +++++- include/fix8/conjure_enum_bitset.hpp | 1 + utests/edgetests.cpp | 1 + utests/unittests.cpp | 1 + 5 files changed, 27 insertions(+), 5 deletions(-) diff --git a/examples/cbenchmark.cpp b/examples/cbenchmark.cpp index 6325242..640bd84 100644 --- a/examples/cbenchmark.cpp +++ b/examples/cbenchmark.cpp @@ -32,16 +32,31 @@ // call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat" // cl /nologo /MD /std:c++latest /Bt+ /I ..\include ..\examples\cbenchmark.cpp|find "c1xx.dll" //---------------------------------------------------------------------------------------- -#include #define FIX8_CONJURE_ENUM_ALL_OPTIMIZATIONS #include //----------------------------------------------------------------------------------------- -FIX8_CONJURE_ENUM_SET_RANGE_INTS(std::errc, 0, 71) +enum class numbers +{ + zero, one, two, three, four, + five, six, seven, eight, nine, + ten, eleven, twelve, thirteen, fourteen, + fifteen, sixteen, seventeen, eighteen, nineteen, + twenty, twenty_one, twenty_two, twenty_three, twenty_four, + twenty_five, twenty_six, twenty_seven, twenty_eight, twenty_nine, + thirty, thirty_one, thirty_two, thirty_three, thirty_four, + thirty_five, thirty_six, thirty_seven, thirty_eight, thirty_nine, + forty, forty_one, forty_two, forty_three, forty_four, + forty_five, forty_six, forty_seven, forty_eight, forty_nine, + fifty, fifty_one, fifty_two, fifty_three, fifty_four, + fifty_five, fifty_six, fifty_seven, fifty_eight, fifty_nine, + sixty, sixty_one, sixty_two, sixty_three +}; +FIX8_CONJURE_ENUM_SET_RANGE(numbers::zero, numbers::sixty_three); -int test_conjure_enum(std::errc err) +int test_conjure_enum(numbers num) { - return FIX8::conjure_enum::enum_to_string(err).size(); + return FIX8::conjure_enum::enum_to_string(num).size(); } int main(void) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 5f77167..e18d060 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -339,7 +339,11 @@ class conjure_enum final : public static_only } static constexpr std::optional int_to_enum(int value) noexcept { - return contains(static_cast(value)) ? static_cast(value) : std::optional{}; + return contains(enum_cast(value)) ? enum_cast(value) : std::optional{}; + } + static constexpr T enum_cast(int value) noexcept + { + return static_cast(value); } // index diff --git a/include/fix8/conjure_enum_bitset.hpp b/include/fix8/conjure_enum_bitset.hpp index 0dc9db3..cef1b75 100644 --- a/include/fix8/conjure_enum_bitset.hpp +++ b/include/fix8/conjure_enum_bitset.hpp @@ -51,6 +51,7 @@ concept valid_bitset_enum = valid_enum and requires(T) requires conjure_enum::is_continuous(); requires conjure_enum::get_actual_enum_min_value() == 0; requires conjure_enum::get_actual_enum_max_value() < conjure_enum::count(); + requires std::bit_ceil(static_cast(conjure_enum::get_actual_enum_max_value())) >= conjure_enum::count(); }; //----------------------------------------------------------------------------------------- diff --git a/utests/edgetests.cpp b/utests/edgetests.cpp index 391562c..fc07f9d 100644 --- a/utests/edgetests.cpp +++ b/utests/edgetests.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include //----------------------------------------------------------------------------------------- diff --git a/utests/unittests.cpp b/utests/unittests.cpp index 8214709..e94158c 100644 --- a/utests/unittests.cpp +++ b/utests/unittests.cpp @@ -328,6 +328,7 @@ TEST_CASE("int_to_enum") REQUIRE(conjure_enum::int_to_enum(11).value_or(static_cast(100)) == static_cast(100)); REQUIRE(conjure_enum::int_to_enum(4).value() == numbers::four); REQUIRE(conjure_enum::int_to_enum(11).value_or(static_cast(100)) == static_cast(100)); + REQUIRE(conjure_enum::enum_cast(150) == static_cast(150)); } //----------------------------------------------------------------------------------------- From f77c808036faf51bf77ed505d31b61d9a6307fb0 Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 21 Aug 2024 07:14:07 +1000 Subject: [PATCH 131/235] updated --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 003e148..0901dee 100644 --- a/README.md +++ b/README.md @@ -1817,7 +1817,7 @@ Compilation (2 times): 0 ms: __gnu_cxx::__to_xstring<$> (1 times, avg 0 ms) **** Functions that took longest to compile: - 0 ms: test_conjure_enum(std::errc) (/home/davidd/prog/conjure_enum_tclass/examples/cbenchmark.cpp) + 0 3s: test_conjure_enum(std::errc) (/home/davidd/prog/conjure_enum_tclass/examples/cbenchmark.cpp) **** Function sets that took longest to compile / optimize: @@ -1840,9 +1840,9 @@ For `magic_enum` we created a separate repo (see [here](https://github.com/fix8m | Compiler | `conjure_enum` (secs) | `magic_enum` (secs)| Notes | | :--- | :--- | :--- |:--- | -| MSVC | 0.441 | 0.385 | using cl from command prompt| +| MSVC | 0.376 | 0.343 | using cl from command prompt| |_command_ | `cl /nologo /MD /std:c++latest /Bt+ /I ..\include ..\examples\cbenchmark.cpp\|find "c1xx.dll"` | `cl /nologo /MD /std:c++latest /Bt+ -I build\_deps\magic_enum-src\include cbenchmark.cpp\|find "c1xx.dll"`|| -| clang | 0.4 | 0.4 | using ClangBuildAnalyzer| +| clang | 0.3 | 0.3 | using ClangBuildAnalyzer| |_command_|`make`; `ClangBuildAnalyzerLoc=~/prog/ClangBuildAnalyzer/build ArtifactLoc=build_clang examples/cbenchmark.sh`|`make`; `ClangBuildAnalyzerLoc=~/prog/ClangBuildAnalyzer/build ArtifactLoc=build_clang ./cbenchmark.sh`|| ## Notes @@ -1854,7 +1854,7 @@ For `magic_enum` we created a separate repo (see [here](https://github.com/fix8m - `conjure_enum`: minimal build ## Discussion -For MSVC, `magic_enum` compilation times a slighly better than `conjure_enum` (around %10). For clang the results are identical. +For MSVC, `magic_enum` compilation times a slighly better than `conjure_enum` (around %9). For clang the results are identical. From a compilation performance perspective, `conjure_enum` roughly matches the performance of `magic_enum`. --- @@ -1863,7 +1863,7 @@ From a compilation performance perspective, `conjure_enum` roughly matches the p | :--- | :--- | :--- | ---: | | [gcc](https://gcc.gnu.org/projects/cxx-status.html) | `11`, `12`, `13`, `14`| `std::format` not complete in `11`, `12` | `<= 10` | | [clang](https://clang.llvm.org/cxx_status.html) | `15`, `16`, `17`, `18`| Catch2 needs `cxx_std_20` in `15` | `<= 14` | -| [msvc](https://learn.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance) | `16`, `17` | Visual Studio 2019,2022, latest `17.11.0`| `<= 16.9`| +| [msvc](https://learn.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance) | `16`, `17` | Visual Studio 2019,2022, latest `17.11.1`| `<= 16.9`| | [xcode](https://developer.apple.com/support/xcode/) | `15` | Apple LLVM 15.0.0, some issues with `constexpr`, workarounds| `<= 14`| # 11. Compiler issues From 4176b5ddee4bdb4a0da670db5611346d1cff5afc Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 21 Aug 2024 07:15:23 +1000 Subject: [PATCH 132/235] updated --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0901dee..125a738 100644 --- a/README.md +++ b/README.md @@ -1840,9 +1840,9 @@ For `magic_enum` we created a separate repo (see [here](https://github.com/fix8m | Compiler | `conjure_enum` (secs) | `magic_enum` (secs)| Notes | | :--- | :--- | :--- |:--- | -| MSVC | 0.376 | 0.343 | using cl from command prompt| +| **MSVC** | 0.376 | 0.343 | using cl from command prompt| |_command_ | `cl /nologo /MD /std:c++latest /Bt+ /I ..\include ..\examples\cbenchmark.cpp\|find "c1xx.dll"` | `cl /nologo /MD /std:c++latest /Bt+ -I build\_deps\magic_enum-src\include cbenchmark.cpp\|find "c1xx.dll"`|| -| clang | 0.3 | 0.3 | using ClangBuildAnalyzer| +| **clang** | 0.3 | 0.3 | using ClangBuildAnalyzer| |_command_|`make`; `ClangBuildAnalyzerLoc=~/prog/ClangBuildAnalyzer/build ArtifactLoc=build_clang examples/cbenchmark.sh`|`make`; `ClangBuildAnalyzerLoc=~/prog/ClangBuildAnalyzer/build ArtifactLoc=build_clang ./cbenchmark.sh`|| ## Notes From 6ffb62181bafb5924aaf35a9c7bdc31a87a3b70e Mon Sep 17 00:00:00 2001 From: David Dight Date: Fri, 23 Aug 2024 07:07:05 +1000 Subject: [PATCH 133/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 125a738..658428e 100644 --- a/README.md +++ b/README.md @@ -1023,7 +1023,7 @@ All of the standard accessors and mutators are supported. | `to_ullong` | convert to `unsigned long long` | | `count` | count of bits on | | `size` | number of bits in bitset | -| `operator[]` | test bit at position | +| `operator[]` | set or test bit at position | | `any` | return `true` if any bit is on | | `all` | return `true` if all bits are on | | `none` | return `true` if no bits are on | From 26ab83ee8c07f00233ca3c5162c0faf02444c542 Mon Sep 17 00:00:00 2001 From: David Dight Date: Fri, 23 Aug 2024 07:07:23 +1000 Subject: [PATCH 134/235] pre-rel 1.1c --- include/fix8/conjure_enum_bitset.hpp | 53 ++++++++++++++++++++++++---- utests/unittests.cpp | 5 +++ 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/include/fix8/conjure_enum_bitset.hpp b/include/fix8/conjure_enum_bitset.hpp index cef1b75..1718df9 100644 --- a/include/fix8/conjure_enum_bitset.hpp +++ b/include/fix8/conjure_enum_bitset.hpp @@ -61,8 +61,41 @@ concept valid_bitset_enum = valid_enum and requires(T) template class enum_bitset { - using U = std::underlying_type_t; static constexpr auto countof { conjure_enum::count() }; + using U = std::conditional_t>>>; + static_assert(std::integral, "requested bitset overflow"); + + template + class _reference + { + R& _owner; + std::size_t _idx; + constexpr _reference(R& obj, std::size_t idx) noexcept : _owner(obj), _idx(idx) {} + friend class enum_bitset; + + public: + constexpr _reference& operator=(bool val) noexcept + { + if (val) + _owner.set(_idx); + else + _owner.reset(_idx); + return *this; + } + + constexpr _reference& operator=(const _reference& val) noexcept + { + if (this == &val) + return *this; + *this = static_cast(val); + return *this; + } + + constexpr operator bool() const noexcept { return _owner.test(_idx); } + }; template static constexpr U to_underlying() noexcept { return static_cast(val); } // C++23: upgrade to std::to_underlying @@ -71,14 +104,20 @@ class enum_bitset U _present{}; public: + using enum_bitset_underlying_type = U; + using reference = _reference; + using const_reference = _reference; + explicit constexpr enum_bitset(U bits) noexcept : _present(bits) {} constexpr enum_bitset(std::string_view from, bool anyscope=false, char sep='|', bool ignore_errors=true) : _present(factory(from, anyscope, sep, ignore_errors)) {} template + requires (sizeof...(E) > 1) constexpr enum_bitset(E... comp) noexcept : _present((0u | ... | (1 << to_underlying(comp)))) {} template + requires (sizeof...(I) > 1) constexpr enum_bitset(I... comp) noexcept : _present((0u | ... | (1 << comp))) {} constexpr enum_bitset() = default; @@ -91,8 +130,10 @@ class enum_bitset constexpr U to_ulong() const noexcept { return _present; } constexpr unsigned long long to_ullong() const noexcept { return _present; } - constexpr bool operator[](std::size_t pos) const noexcept { return test(pos); } - constexpr bool operator[](T what) const noexcept { return test(what); } + constexpr auto operator[](std::size_t pos) noexcept { return reference(*this, pos); } + constexpr auto operator[](std::size_t pos) const noexcept { return const_reference(*this, pos); } + constexpr auto operator[](T what) noexcept { return reference(*this, to_underlying(what)); } + constexpr auto operator[](T what) const noexcept { return const_reference(*this, to_underlying(what)); } /// set constexpr void set(U pos, bool value=true) noexcept { value ? _present |= 1 << pos : _present &= ~(1 << pos); } @@ -206,9 +247,9 @@ class enum_bitset constexpr enum_bitset operator&(T other) const noexcept { return enum_bitset(_present & 1 << to_underlying(other)); } constexpr enum_bitset operator|(T other) const noexcept { return enum_bitset(_present | 1 << to_underlying(other)); } constexpr enum_bitset operator^(T other) const noexcept { return enum_bitset(_present ^ 1 << to_underlying(other)); } - constexpr enum_bitset operator&(U other) const noexcept { return enum_bitset(_present & other); } - constexpr enum_bitset operator|(U other) const noexcept { return enum_bitset(_present | other); } - constexpr enum_bitset operator^(U other) const noexcept { return enum_bitset(_present ^ other); } + //constexpr enum_bitset operator&(U other) const noexcept { return enum_bitset(_present & other); } + //constexpr enum_bitset operator|(U other) const noexcept { return enum_bitset(_present | other); } + //constexpr enum_bitset operator^(U other) const noexcept { return enum_bitset(_present ^ other); } constexpr enum_bitset operator~() const noexcept { return enum_bitset(~_present & all_bits); } /// for_each, for_each_n diff --git a/utests/unittests.cpp b/utests/unittests.cpp index e94158c..526f15a 100644 --- a/utests/unittests.cpp +++ b/utests/unittests.cpp @@ -656,6 +656,11 @@ TEST_CASE("enum_bitset ops") REQUIRE((ed ^ numbers::one).to_ulong() == 0b010); ed ^= numbers::one; REQUIRE(ed.to_ulong() == 0b010); + + ed.reset(); + ed[2] = true; + REQUIRE(ed.test(numbers::two)); + REQUIRE(ed[2] == true); } //----------------------------------------------------------------------------------------- From cba7a1b491070c327fd03b0dac4d609653e786f9 Mon Sep 17 00:00:00 2001 From: David Dight Date: Fri, 23 Aug 2024 10:57:37 +1000 Subject: [PATCH 135/235] updated --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 658428e..8a4d4c4 100644 --- a/README.md +++ b/README.md @@ -1023,7 +1023,7 @@ All of the standard accessors and mutators are supported. | `to_ullong` | convert to `unsigned long long` | | `count` | count of bits on | | `size` | number of bits in bitset | -| `operator[]` | set or test bit at position | +| `operator[]` | set or test bit at position or enum value | | `any` | return `true` if any bit is on | | `all` | return `true` if all bits are on | | `none` | return `true` if no bits are on | @@ -1055,6 +1055,10 @@ std::cout << std::boolalpha << eb.all_of(numbers::zero,numbers::nine) << '\n'; std::cout << eb << '\n'; eb.reset(numbers::nine) std::cout << ec << '\n'; +eb.reset(); +eb[2] = true; +eb[numbers::three] = true; +std::cout << eb << '\n'; ``` _output_ ``` @@ -1065,6 +1069,7 @@ true true 1000000001 0000000001 +0000001100 ``` ## d) Other functions ### i. `operator bool` From d1817b13f4e37c0d7af2599c470bdc1d85bba2d4 Mon Sep 17 00:00:00 2001 From: David Dight Date: Fri, 23 Aug 2024 10:57:43 +1000 Subject: [PATCH 136/235] pre-rel 1.1c --- utests/unittests.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/utests/unittests.cpp b/utests/unittests.cpp index 526f15a..64015f2 100644 --- a/utests/unittests.cpp +++ b/utests/unittests.cpp @@ -661,6 +661,10 @@ TEST_CASE("enum_bitset ops") ed[2] = true; REQUIRE(ed.test(numbers::two)); REQUIRE(ed[2] == true); + ed.reset(); + ed[numbers::two] = true; + REQUIRE(ed.test(numbers::two)); + REQUIRE(ed[2] == true); } //----------------------------------------------------------------------------------------- From 22b416096dff53ac56334ef96ac9d9f51c6e3ad4 Mon Sep 17 00:00:00 2001 From: David Dight Date: Fri, 23 Aug 2024 11:07:29 +1000 Subject: [PATCH 137/235] pre-rel 1.1c --- include/fix8/conjure_enum_bitset.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fix8/conjure_enum_bitset.hpp b/include/fix8/conjure_enum_bitset.hpp index 1718df9..7f37343 100644 --- a/include/fix8/conjure_enum_bitset.hpp +++ b/include/fix8/conjure_enum_bitset.hpp @@ -72,7 +72,7 @@ class enum_bitset class _reference { R& _owner; - std::size_t _idx; + U _idx; constexpr _reference(R& obj, std::size_t idx) noexcept : _owner(obj), _idx(idx) {} friend class enum_bitset; @@ -94,7 +94,7 @@ class enum_bitset return *this; } - constexpr operator bool() const noexcept { return _owner.test(_idx); } + constexpr operator bool() const noexcept { return static_cast(_owner.test(_idx)); } }; template From d44a10595135d1b5ee5bea56b524a1791caced9a Mon Sep 17 00:00:00 2001 From: David Dight Date: Fri, 23 Aug 2024 11:10:26 +1000 Subject: [PATCH 138/235] pre-rel 1.1c --- include/fix8/conjure_enum_bitset.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fix8/conjure_enum_bitset.hpp b/include/fix8/conjure_enum_bitset.hpp index 7f37343..9f4d068 100644 --- a/include/fix8/conjure_enum_bitset.hpp +++ b/include/fix8/conjure_enum_bitset.hpp @@ -73,7 +73,7 @@ class enum_bitset { R& _owner; U _idx; - constexpr _reference(R& obj, std::size_t idx) noexcept : _owner(obj), _idx(idx) {} + constexpr _reference(R& obj, U idx) noexcept : _owner(obj), _idx(idx) {} friend class enum_bitset; public: From bf036e1e85a7e4bc397a9f88276adc50d2ea8823 Mon Sep 17 00:00:00 2001 From: David Dight Date: Fri, 23 Aug 2024 11:11:32 +1000 Subject: [PATCH 139/235] pre-rel 1.1c --- include/fix8/conjure_enum_bitset.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fix8/conjure_enum_bitset.hpp b/include/fix8/conjure_enum_bitset.hpp index 9f4d068..bd8df62 100644 --- a/include/fix8/conjure_enum_bitset.hpp +++ b/include/fix8/conjure_enum_bitset.hpp @@ -130,8 +130,8 @@ class enum_bitset constexpr U to_ulong() const noexcept { return _present; } constexpr unsigned long long to_ullong() const noexcept { return _present; } - constexpr auto operator[](std::size_t pos) noexcept { return reference(*this, pos); } - constexpr auto operator[](std::size_t pos) const noexcept { return const_reference(*this, pos); } + constexpr auto operator[](U pos) noexcept { return reference(*this, pos); } + constexpr auto operator[](U pos) const noexcept { return const_reference(*this, pos); } constexpr auto operator[](T what) noexcept { return reference(*this, to_underlying(what)); } constexpr auto operator[](T what) const noexcept { return const_reference(*this, to_underlying(what)); } From 3b8d3663366f282898e6e3a3a6cf39ccdf534c1b Mon Sep 17 00:00:00 2001 From: David Dight Date: Fri, 23 Aug 2024 11:17:26 +1000 Subject: [PATCH 140/235] pre-rel 1.1c --- include/fix8/conjure_enum_bitset.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/fix8/conjure_enum_bitset.hpp b/include/fix8/conjure_enum_bitset.hpp index bd8df62..cfa7b07 100644 --- a/include/fix8/conjure_enum_bitset.hpp +++ b/include/fix8/conjure_enum_bitset.hpp @@ -204,28 +204,28 @@ class enum_bitset constexpr bool any_of() const noexcept { return (... || test()); } template - constexpr bool any_of(I...comp) const noexcept { return (... || test(comp)); } + constexpr bool any_of(I...comp) const noexcept { return (... || test(U(comp))); } template - constexpr bool any_of(E...comp) const noexcept { return (... || test(comp)); } + constexpr bool any_of(E...comp) const noexcept { return (... || test(U(comp))); } template constexpr bool all_of() const noexcept { return (... && test()); } template - constexpr bool all_of(I...comp) const noexcept { return (... && test(comp)); } + constexpr bool all_of(I...comp) const noexcept { return (... && test(U(comp))); } template - constexpr bool all_of(E...comp) const noexcept { return (... && test(comp)); } + constexpr bool all_of(E...comp) const noexcept { return (... && test(U(comp))); } template constexpr bool none_of() const noexcept { return (... && !test()); } template - constexpr bool none_of(I...comp) const noexcept { return (... && !test(comp)); } + constexpr bool none_of(I...comp) const noexcept { return (... && !test(U(comp))); } template - constexpr bool none_of(E...comp) const noexcept { return (... && !test(comp)); } + constexpr bool none_of(E...comp) const noexcept { return (... && !test(U(comp))); } constexpr bool any() const noexcept { return count(); } constexpr bool all() const noexcept { return _present == all_bits; } From 95862a2a5e9b5a53b339cba58c47147184d0ac78 Mon Sep 17 00:00:00 2001 From: David Dight Date: Fri, 23 Aug 2024 12:28:40 +1000 Subject: [PATCH 141/235] pre-rel 1.1c --- include/fix8/conjure_enum.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index e18d060..280db08 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -365,7 +365,8 @@ class conjure_enum final : public static_only { if constexpr (is_continuous()) return in_range(value); - return std::binary_search(values.cbegin(), values.cend(), value, _value_comp); + else + return std::binary_search(values.cbegin(), values.cend(), value, _value_comp); } static constexpr bool contains(std::string_view str) noexcept { From 55f243eb8d9e6b1c8992fd04f158590fb78444ca Mon Sep 17 00:00:00 2001 From: David Dight Date: Fri, 23 Aug 2024 12:29:38 +1000 Subject: [PATCH 142/235] pre-rel 1.1c --- include/fix8/conjure_enum.hpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 280db08..78b10b1 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -351,8 +351,11 @@ class conjure_enum final : public static_only { if constexpr (is_continuous()) return in_range(value) ? enum_to_underlying(value) - enum_to_underlying(min_v) : std::optional{}; - const auto [begin,end] { std::equal_range(entries.cbegin(), entries.cend(), enum_tuple(value, std::string_view()), _tuple_comp) }; - return begin != end ? &*begin - &*entries.cbegin() : std::optional{}; + else + { + const auto [begin,end] { std::equal_range(entries.cbegin(), entries.cend(), enum_tuple(value, std::string_view()), _tuple_comp) }; + return begin != end ? &*begin - &*entries.cbegin() : std::optional{}; + } } template static constexpr std::optional index() noexcept { return index(e); } From 4768e08eded75ee7a545704cbf3f9034615a1ce9 Mon Sep 17 00:00:00 2001 From: David Dight Date: Fri, 23 Aug 2024 12:30:30 +1000 Subject: [PATCH 143/235] pre-rel 1.1c --- examples/cbenchmark.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cbenchmark.cpp b/examples/cbenchmark.cpp index 640bd84..d396bcf 100644 --- a/examples/cbenchmark.cpp +++ b/examples/cbenchmark.cpp @@ -54,7 +54,7 @@ enum class numbers }; FIX8_CONJURE_ENUM_SET_RANGE(numbers::zero, numbers::sixty_three); -int test_conjure_enum(numbers num) +auto test_conjure_enum(numbers num) { return FIX8::conjure_enum::enum_to_string(num).size(); } From 258130aeeb12c02923cba7823475023511bea87e Mon Sep 17 00:00:00 2001 From: David Dight Date: Fri, 23 Aug 2024 16:08:39 +1000 Subject: [PATCH 144/235] updated --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8a4d4c4..f66bdfe 100644 --- a/README.md +++ b/README.md @@ -890,13 +890,13 @@ false # 4. API and Examples using `enum_bitset` `enum_bitset` is a convenient way of creating bitsets based on `std::bitset`. It uses your enum (scoped or unscoped) for the bit positions (and names). -> [!WARNING] +> [!NOTE] > - Your enum sequence _must_ be 0 based > - Continuous > - The last value must be less than the count of enumerations > - This implementation is limited to 64 bits > -> We decided on this restriction for both simplicity and practicality - bitsets only really make sense when represented in this manner. +> We decided on these restrictions for both simplicity and practicality - bitsets only really make sense when represented in this manner. > [!IMPORTANT] > You must include From 83d6ba31b4907eef7c3b663e53b926b220d72fc6 Mon Sep 17 00:00:00 2001 From: David Dight Date: Fri, 23 Aug 2024 16:15:45 +1000 Subject: [PATCH 145/235] updated --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index f66bdfe..e272bf6 100644 --- a/README.md +++ b/README.md @@ -109,6 +109,17 @@ enum component1 { scheme, authority, userinfo, user, password, host, port, path= enum class numbers { zero, one, two, three, four, five, six, seven, eight, nine }; ``` +> [!IMPORTANT] +> Your type _must_ be an enum, satisfying +> ```C++ +>template +>concept valid_enum = requires(T) +>{ +> requires std::same_as>; +> requires std::is_enum_v; +>}; +> ``` + ## a) `enum_to_string` ```c++ static constexpr std::string_view enum_to_string(T value, bool noscope=false); From 9996065361e1bd36ead63928a4487705fa6de955 Mon Sep 17 00:00:00 2001 From: David Dight Date: Fri, 23 Aug 2024 16:18:46 +1000 Subject: [PATCH 146/235] updated --- README.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e272bf6..00d8234 100644 --- a/README.md +++ b/README.md @@ -110,7 +110,7 @@ enum class numbers { zero, one, two, three, four, five, six, seven, eight, nine ``` > [!IMPORTANT] -> Your type _must_ be an enum, satisfying +> Your type _must_ be an enum, satisfying: > ```C++ >template >concept valid_enum = requires(T) @@ -916,6 +916,19 @@ for the bit positions (and names). > #include > ``` +> [!IMPORTANT] +> Your enum _must_ satisfy the following: +> ```C++ +>template +>concept valid_bitset_enum = valid_enum and requires(T) +>{ +> requires conjure_enum::is_continuous(); +> requires conjure_enum::get_actual_enum_min_value() == 0; +> requires conjure_enum::get_actual_enum_max_value() < conjure_enum::count(); +> requires std::bit_ceil(static_cast(conjure_enum::get_actual_enum_max_value())) >= conjure_enum::count(); +>}; +``` + ## a) Creating an `enum_bitset` ```c++ constexpr enum_bitset() = default; From cb929549675c1c03de83cd70713c69f48102ee0a Mon Sep 17 00:00:00 2001 From: David Dight Date: Fri, 23 Aug 2024 16:19:39 +1000 Subject: [PATCH 147/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 00d8234..5514a17 100644 --- a/README.md +++ b/README.md @@ -118,7 +118,7 @@ enum class numbers { zero, one, two, three, four, five, six, seven, eight, nine > requires std::same_as>; > requires std::is_enum_v; >}; -> ``` +``` ## a) `enum_to_string` ```c++ From 95823e25034b99b8afda3053e3abbd91ba8f316d Mon Sep 17 00:00:00 2001 From: David Dight Date: Fri, 23 Aug 2024 16:20:31 +1000 Subject: [PATCH 148/235] updated --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5514a17..7188940 100644 --- a/README.md +++ b/README.md @@ -118,7 +118,7 @@ enum class numbers { zero, one, two, three, four, five, six, seven, eight, nine > requires std::same_as>; > requires std::is_enum_v; >}; -``` +>``` ## a) `enum_to_string` ```c++ @@ -927,7 +927,7 @@ for the bit positions (and names). > requires conjure_enum::get_actual_enum_max_value() < conjure_enum::count(); > requires std::bit_ceil(static_cast(conjure_enum::get_actual_enum_max_value())) >= conjure_enum::count(); >}; -``` +>``` ## a) Creating an `enum_bitset` ```c++ From 0b5defa0914bf6603a57a4514a9eb3cb63a9eb93 Mon Sep 17 00:00:00 2001 From: David Dight Date: Fri, 23 Aug 2024 16:20:55 +1000 Subject: [PATCH 149/235] updated --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 7188940..41a3798 100644 --- a/README.md +++ b/README.md @@ -915,8 +915,6 @@ for the bit positions (and names). > #include > #include > ``` - -> [!IMPORTANT] > Your enum _must_ satisfy the following: > ```C++ >template From 75f16bda155088fd1df35267d620dab1043ca58f Mon Sep 17 00:00:00 2001 From: David Dight Date: Sat, 24 Aug 2024 06:35:04 +1000 Subject: [PATCH 150/235] updated --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 41a3798..ada7ccc 100644 --- a/README.md +++ b/README.md @@ -923,7 +923,6 @@ for the bit positions (and names). > requires conjure_enum::is_continuous(); > requires conjure_enum::get_actual_enum_min_value() == 0; > requires conjure_enum::get_actual_enum_max_value() < conjure_enum::count(); -> requires std::bit_ceil(static_cast(conjure_enum::get_actual_enum_max_value())) >= conjure_enum::count(); >}; >``` From 5bdeee640b8a6126d14685711b9e4c59624c85e8 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sat, 24 Aug 2024 15:48:04 +1000 Subject: [PATCH 151/235] pre-rel 1.1c --- CMakeLists.txt | 4 +++- include/fix8/conjure_enum_bitset.hpp | 27 +++++++++++---------------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fa679ec..7377db2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,7 +33,9 @@ project (conjure_enum LANGUAGES CXX HOMEPAGE_URL https://github.com/fix8mt/conjure_enum DESCRIPTION "Lightweight C++20 enum and typename reflection" - VERSION 1.0.2) + VERSION 1.1.0) + +message("${CMAKE_PROJECT_NAME} version ${CMAKE_PROJECT_VERSION}") # to disable strip: # cmake -DBUILD_STRIP_EXE=false .. diff --git a/include/fix8/conjure_enum_bitset.hpp b/include/fix8/conjure_enum_bitset.hpp index cfa7b07..71a2b5a 100644 --- a/include/fix8/conjure_enum_bitset.hpp +++ b/include/fix8/conjure_enum_bitset.hpp @@ -38,7 +38,9 @@ //---------------------------------------------------------------------------------------- #include -#include +#include +#include +#include #include //----------------------------------------------------------------------------------------- @@ -51,7 +53,6 @@ concept valid_bitset_enum = valid_enum and requires(T) requires conjure_enum::is_continuous(); requires conjure_enum::get_actual_enum_min_value() == 0; requires conjure_enum::get_actual_enum_max_value() < conjure_enum::count(); - requires std::bit_ceil(static_cast(conjure_enum::get_actual_enum_max_value())) >= conjure_enum::count(); }; //----------------------------------------------------------------------------------------- @@ -79,22 +80,18 @@ class enum_bitset public: constexpr _reference& operator=(bool val) noexcept { - if (val) - _owner.set(_idx); - else - _owner.reset(_idx); + val ? _owner.set(_idx) : _owner.reset(_idx); return *this; } constexpr _reference& operator=(const _reference& val) noexcept { - if (this == &val) - return *this; - *this = static_cast(val); + if (this != &val) + *this = static_cast(val); return *this; } - constexpr operator bool() const noexcept { return static_cast(_owner.test(_idx)); } + constexpr operator bool() const noexcept { return _owner.test(_idx); } }; template @@ -127,13 +124,14 @@ class enum_bitset { return std::popcount(static_cast>(_present)); } // C++23: upgrade to std::bitset when count is constexpr constexpr std::size_t not_count() const noexcept { return countof - count(); } constexpr std::size_t size() const noexcept { return countof; } - constexpr U to_ulong() const noexcept { return _present; } + constexpr unsigned long to_ulong() const noexcept { return _present; } constexpr unsigned long long to_ullong() const noexcept { return _present; } + // subscript constexpr auto operator[](U pos) noexcept { return reference(*this, pos); } constexpr auto operator[](U pos) const noexcept { return const_reference(*this, pos); } - constexpr auto operator[](T what) noexcept { return reference(*this, to_underlying(what)); } - constexpr auto operator[](T what) const noexcept { return const_reference(*this, to_underlying(what)); } + constexpr auto operator[](T what) noexcept { return (*this)[to_underlying(what)]; } + constexpr auto operator[](T what) const noexcept { return (*this)[to_underlying(what)]; } /// set constexpr void set(U pos, bool value=true) noexcept { value ? _present |= 1 << pos : _present &= ~(1 << pos); } @@ -247,9 +245,6 @@ class enum_bitset constexpr enum_bitset operator&(T other) const noexcept { return enum_bitset(_present & 1 << to_underlying(other)); } constexpr enum_bitset operator|(T other) const noexcept { return enum_bitset(_present | 1 << to_underlying(other)); } constexpr enum_bitset operator^(T other) const noexcept { return enum_bitset(_present ^ 1 << to_underlying(other)); } - //constexpr enum_bitset operator&(U other) const noexcept { return enum_bitset(_present & other); } - //constexpr enum_bitset operator|(U other) const noexcept { return enum_bitset(_present | other); } - //constexpr enum_bitset operator^(U other) const noexcept { return enum_bitset(_present ^ other); } constexpr enum_bitset operator~() const noexcept { return enum_bitset(~_present & all_bits); } /// for_each, for_each_n From a36f1fb51e696c26e952ecec5f089508706501f8 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sat, 24 Aug 2024 15:57:46 +1000 Subject: [PATCH 152/235] updated --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ada7ccc..b4ab031 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,7 @@ > Even better in [full read view](./README.md) of this page. > > For the latest cutting edge changes, see the [dev branch](https://github.com/fix8mt/conjure_enum/tree/dev). +> You can view the changes [here](https://github.com/fix8mt/conjure_enum/compare/master..dev). --- # 2. Introduction From d4a60035ac94aed14410d65eb240d5a805c4cb94 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sun, 25 Aug 2024 21:21:01 +1000 Subject: [PATCH 153/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b4ab031..915bb96 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ unlocked the potential of [`constexpr` algorithms](https://www.open-std.org/jtc1 - scoped and unscoped enums - enums with **aliases** and **gaps** - anonymous and named namespaced enums and types - - custom enum ranges + - custom [enum ranges](#ii.-using-enum_range) - ***Easy to Use***: Class-based approach with intuitive syntax - ***Convenient***: `enum_bitset` provides an enhanced enum aware `std::bitset` (see 3 above) - ***Useful***: `conjure_type` gives you the type string of _any type!_ (see 4 above) From 2495e4708d033e62f4a1487692e8627e4562b003 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sun, 25 Aug 2024 21:21:44 +1000 Subject: [PATCH 154/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 915bb96..a0bbc43 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ unlocked the potential of [`constexpr` algorithms](https://www.open-std.org/jtc1 - scoped and unscoped enums - enums with **aliases** and **gaps** - anonymous and named namespaced enums and types - - custom [enum ranges](#ii.-using-enum_range) + - custom [enum ranges](#ii-using-enum_range) - ***Easy to Use***: Class-based approach with intuitive syntax - ***Convenient***: `enum_bitset` provides an enhanced enum aware `std::bitset` (see 3 above) - ***Useful***: `conjure_type` gives you the type string of _any type!_ (see 4 above) From 384b24570e1a289869339eb3d68fea259387d9bc Mon Sep 17 00:00:00 2001 From: David Dight Date: Sun, 25 Aug 2024 21:27:53 +1000 Subject: [PATCH 155/235] updated --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index a0bbc43..1b1bfe6 100644 --- a/README.md +++ b/README.md @@ -1562,6 +1562,20 @@ FIX8_CONJURE_ENUM_SET_RANGE_INTS(numbers, 0, 7) FIX8_CONJURE_ENUM_SET_RANGE(numbers::first, numbers::eighth) ``` +### iv. using `T::ce_first` and `T::ce_last` +Another approach to setting a custom range for an enum is to alias the first and last enum values in your enum definition +using `ce_first` and `ce_last`. For example: +```c++ +enum class foo { one, two, three, four, five, size, seven, eight, ce_first=one, ce_last=eight }; +std::cout << conjure_enum::get_enum_min_value() << '/' << conjure_enum::get_enum_max_value() << '\n'; +std::cout << conjure_enum::get_actual_enum_min_value() << '/' << conjure_enum::get_actual_enum_max_value() << '\n'; +``` +_output_ +```CSV +0/7 +0/7 +``` + ## b) Choosing the minimal build ```c++ #define FIX8_CONJURE_ENUM_MINIMAL From 45145ad7d86be831d5eceae954afdc18beccfcd1 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sun, 25 Aug 2024 21:30:08 +1000 Subject: [PATCH 156/235] updated --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1b1bfe6..87da634 100644 --- a/README.md +++ b/README.md @@ -1567,8 +1567,9 @@ Another approach to setting a custom range for an enum is to alias the first and using `ce_first` and `ce_last`. For example: ```c++ enum class foo { one, two, three, four, five, size, seven, eight, ce_first=one, ce_last=eight }; -std::cout << conjure_enum::get_enum_min_value() << '/' << conjure_enum::get_enum_max_value() << '\n'; -std::cout << conjure_enum::get_actual_enum_min_value() << '/' << conjure_enum::get_actual_enum_max_value() << '\n'; +using fn = conjure_enum; +std::cout << fn::get_enum_min_value() << '/' << fn::get_enum_max_value() << '\n'; +std::cout << fn::get_actual_enum_min_value() << '/' << fn::get_actual_enum_max_value() << '\n'; ``` _output_ ```CSV From f3ac63fafa486c0fcef542631d352e2824ad0dcc Mon Sep 17 00:00:00 2001 From: David Dight Date: Sun, 25 Aug 2024 21:33:08 +1000 Subject: [PATCH 157/235] updated --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 87da634..d48ed2e 100644 --- a/README.md +++ b/README.md @@ -1564,12 +1564,12 @@ FIX8_CONJURE_ENUM_SET_RANGE(numbers::first, numbers::eighth) ### iv. using `T::ce_first` and `T::ce_last` Another approach to setting a custom range for an enum is to alias the first and last enum values in your enum definition -using `ce_first` and `ce_last`. For example: +using `ce_first` and `ce_last`. `conjure_enum` will use these values to set the enum range. For example: ```c++ -enum class foo { one, two, three, four, five, size, seven, eight, ce_first=one, ce_last=eight }; -using fn = conjure_enum; -std::cout << fn::get_enum_min_value() << '/' << fn::get_enum_max_value() << '\n'; -std::cout << fn::get_actual_enum_min_value() << '/' << fn::get_actual_enum_max_value() << '\n'; +enum class range_test { first, second, third, fourth, fifth, sixth, seventh, eighth, ce_first=first, ce_last=eighth }; +using rt = conjure_enum; +std::cout << rt::get_enum_min_value() << '/' << rt::get_enum_max_value() << '\n'; +std::cout << rt::get_actual_enum_min_value() << '/' << rt::get_actual_enum_max_value() << '\n'; ``` _output_ ```CSV From eb9ec60f8b23cf194fc091aa73cf42808d5baf49 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sun, 25 Aug 2024 21:37:56 +1000 Subject: [PATCH 158/235] updated --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d48ed2e..8d37dc1 100644 --- a/README.md +++ b/README.md @@ -1564,7 +1564,9 @@ FIX8_CONJURE_ENUM_SET_RANGE(numbers::first, numbers::eighth) ### iv. using `T::ce_first` and `T::ce_last` Another approach to setting a custom range for an enum is to alias the first and last enum values in your enum definition -using `ce_first` and `ce_last`. `conjure_enum` will use these values to set the enum range. For example: +using `ce_first` and `ce_last`. `conjure_enum` will use these values to set the enum range. +You can set either, both or neither. A range value not set will default to the `FIX8_CONJURE_ENUM_MIN_VALUE` or `FIX8_CONJURE_ENUM_MAX_VALUE`. +For example: ```c++ enum class range_test { first, second, third, fourth, fifth, sixth, seventh, eighth, ce_first=first, ce_last=eighth }; using rt = conjure_enum; From 1a362c61759886c574ffc4fa65e728b453729702 Mon Sep 17 00:00:00 2001 From: David Dight Date: Mon, 26 Aug 2024 06:15:47 +1000 Subject: [PATCH 159/235] updated --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 8d37dc1..b83aa9c 100644 --- a/README.md +++ b/README.md @@ -1566,6 +1566,11 @@ FIX8_CONJURE_ENUM_SET_RANGE(numbers::first, numbers::eighth) Another approach to setting a custom range for an enum is to alias the first and last enum values in your enum definition using `ce_first` and `ce_last`. `conjure_enum` will use these values to set the enum range. You can set either, both or neither. A range value not set will default to the `FIX8_CONJURE_ENUM_MIN_VALUE` or `FIX8_CONJURE_ENUM_MAX_VALUE`. + +> [!WARN] +> For unscoped enums, there can only be one enum type with `T::ce_first` and `T::ce_last` defined, due to the open scoping of unscoped +> enums. It is therefore recommended to only use this feature with scoped enumns. + For example: ```c++ enum class range_test { first, second, third, fourth, fifth, sixth, seventh, eighth, ce_first=first, ce_last=eighth }; From ac04be49254e424bdc586fa23ef8f01e3854b53d Mon Sep 17 00:00:00 2001 From: David Dight Date: Mon, 26 Aug 2024 06:16:13 +1000 Subject: [PATCH 160/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b83aa9c..320fb1c 100644 --- a/README.md +++ b/README.md @@ -1567,7 +1567,7 @@ Another approach to setting a custom range for an enum is to alias the first and using `ce_first` and `ce_last`. `conjure_enum` will use these values to set the enum range. You can set either, both or neither. A range value not set will default to the `FIX8_CONJURE_ENUM_MIN_VALUE` or `FIX8_CONJURE_ENUM_MAX_VALUE`. -> [!WARN] +> [!WARNING] > For unscoped enums, there can only be one enum type with `T::ce_first` and `T::ce_last` defined, due to the open scoping of unscoped > enums. It is therefore recommended to only use this feature with scoped enumns. From 617681bdfb50477f5287daf8beda2790bc9de94a Mon Sep 17 00:00:00 2001 From: David Dight Date: Mon, 26 Aug 2024 06:18:39 +1000 Subject: [PATCH 161/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 320fb1c..0d0fb98 100644 --- a/README.md +++ b/README.md @@ -1568,7 +1568,7 @@ using `ce_first` and `ce_last`. `conjure_enum` will use these values to set the You can set either, both or neither. A range value not set will default to the `FIX8_CONJURE_ENUM_MIN_VALUE` or `FIX8_CONJURE_ENUM_MAX_VALUE`. > [!WARNING] -> For unscoped enums, there can only be one enum type with `T::ce_first` and `T::ce_last` defined, due to the open scoping of unscoped +> For unscoped enums, there can only be one enum type with `T::ce_first` and `T::ce_last` defined in any translation unit (ODR), due to the open scoping of unscoped > enums. It is therefore recommended to only use this feature with scoped enumns. For example: From 778e614bda1f08d9082c862f4c64b6be177f99df Mon Sep 17 00:00:00 2001 From: David Dight Date: Mon, 26 Aug 2024 06:19:53 +1000 Subject: [PATCH 162/235] updated --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0d0fb98..0982056 100644 --- a/README.md +++ b/README.md @@ -1569,11 +1569,15 @@ You can set either, both or neither. A range value not set will default to the ` > [!WARNING] > For unscoped enums, there can only be one enum type with `T::ce_first` and `T::ce_last` defined in any translation unit (ODR), due to the open scoping of unscoped -> enums. It is therefore recommended to only use this feature with scoped enumns. +> enums. It is therefore recommended to only use this feature with scoped enums. For example: ```c++ -enum class range_test { first, second, third, fourth, fifth, sixth, seventh, eighth, ce_first=first, ce_last=eighth }; +enum class range_test +{ + first, second, third, fourth, fifth, sixth, seventh, eighth, + ce_first=first, ce_last=eighth +}; using rt = conjure_enum; std::cout << rt::get_enum_min_value() << '/' << rt::get_enum_max_value() << '\n'; std::cout << rt::get_actual_enum_min_value() << '/' << rt::get_actual_enum_max_value() << '\n'; From 8c851bbc1fad7c9dbe8f84eb8bd513cc191c551f Mon Sep 17 00:00:00 2001 From: David Dight Date: Mon, 26 Aug 2024 06:21:00 +1000 Subject: [PATCH 163/235] updated --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0982056..25a78dc 100644 --- a/README.md +++ b/README.md @@ -1575,8 +1575,8 @@ For example: ```c++ enum class range_test { - first, second, third, fourth, fifth, sixth, seventh, eighth, - ce_first=first, ce_last=eighth + first, second, third, fourth, fifth, sixth, seventh, eighth, + ce_first=first, ce_last=eighth }; using rt = conjure_enum; std::cout << rt::get_enum_min_value() << '/' << rt::get_enum_max_value() << '\n'; From 0abab947c6477b65f85ee8a952e215e0b6c6ace2 Mon Sep 17 00:00:00 2001 From: David Dight Date: Mon, 26 Aug 2024 06:56:25 +1000 Subject: [PATCH 164/235] updated --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 25a78dc..fe8f016 100644 --- a/README.md +++ b/README.md @@ -1547,7 +1547,7 @@ struct FIX8::enum_range static_assert(conjure_enum::get_enum_min_value() == 0); static_assert(conjure_enum::get_enum_max_value() == 7); ``` -### iii. `FIX8_CONJURE_ENUM_SET_RANGE_INTS`, `FIX8_CONJURE_ENUM_SET_RANGE` +#### `FIX8_CONJURE_ENUM_SET_RANGE_INTS`, `FIX8_CONJURE_ENUM_SET_RANGE` For convenience, two macros are provided to make it easier to set custom ranges. ```c++ #define FIX8_CONJURE_ENUM_SET_RANGE_INTS(ec,min_int,max_int)... @@ -1562,13 +1562,13 @@ FIX8_CONJURE_ENUM_SET_RANGE_INTS(numbers, 0, 7) FIX8_CONJURE_ENUM_SET_RANGE(numbers::first, numbers::eighth) ``` -### iv. using `T::ce_first` and `T::ce_last` +### iii. using `T::ce_first` and `T::ce_last` Another approach to setting a custom range for an enum is to alias the first and last enum values in your enum definition using `ce_first` and `ce_last`. `conjure_enum` will use these values to set the enum range. You can set either, both or neither. A range value not set will default to the `FIX8_CONJURE_ENUM_MIN_VALUE` or `FIX8_CONJURE_ENUM_MAX_VALUE`. > [!WARNING] -> For unscoped enums, there can only be one enum type with `T::ce_first` and `T::ce_last` defined in any translation unit (ODR), due to the open scoping of unscoped +> With _unscoped_ enums, there can only be one enum type with `T::ce_first` and `T::ce_last` defined in any translation unit (ODR), due to the open scoping of unscoped > enums. It is therefore recommended to only use this feature with scoped enums. For example: From 74a8e7261ee9ddd3d83e0fb649f6d3ac4e778498 Mon Sep 17 00:00:00 2001 From: David Dight Date: Mon, 26 Aug 2024 06:57:17 +1000 Subject: [PATCH 165/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fe8f016..565b341 100644 --- a/README.md +++ b/README.md @@ -1547,7 +1547,7 @@ struct FIX8::enum_range static_assert(conjure_enum::get_enum_min_value() == 0); static_assert(conjure_enum::get_enum_max_value() == 7); ``` -#### `FIX8_CONJURE_ENUM_SET_RANGE_INTS`, `FIX8_CONJURE_ENUM_SET_RANGE` +#### ii.1 `FIX8_CONJURE_ENUM_SET_RANGE_INTS`, `FIX8_CONJURE_ENUM_SET_RANGE` For convenience, two macros are provided to make it easier to set custom ranges. ```c++ #define FIX8_CONJURE_ENUM_SET_RANGE_INTS(ec,min_int,max_int)... From f1107c6c327cbc2a5b6d157297521a4cb2c23a6d Mon Sep 17 00:00:00 2001 From: David Dight Date: Mon, 26 Aug 2024 07:07:37 +1000 Subject: [PATCH 166/235] updated --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 565b341..d2fdfd4 100644 --- a/README.md +++ b/README.md @@ -1547,7 +1547,7 @@ struct FIX8::enum_range static_assert(conjure_enum::get_enum_min_value() == 0); static_assert(conjure_enum::get_enum_max_value() == 7); ``` -#### ii.1 `FIX8_CONJURE_ENUM_SET_RANGE_INTS`, `FIX8_CONJURE_ENUM_SET_RANGE` +#### ii.a `FIX8_CONJURE_ENUM_SET_RANGE_INTS`, `FIX8_CONJURE_ENUM_SET_RANGE` For convenience, two macros are provided to make it easier to set custom ranges. ```c++ #define FIX8_CONJURE_ENUM_SET_RANGE_INTS(ec,min_int,max_int)... @@ -1588,6 +1588,12 @@ _output_ 0/7 ``` +### iv. Which enum limit approach to use +Compilation times increase with the number of enums that use `conjure_enum` in any compilation unit. +- For a simple project with few enums, there is probably no need to set any limits. +- Where the enum is defined elsewhere (say if you are using `std::errc`) then use `enum_range` or one of the convenience macros +- Where you have defined the enum yourself and it is a scoped enum, use `T::ce_first` and `T::ce_last` + ## b) Choosing the minimal build ```c++ #define FIX8_CONJURE_ENUM_MINIMAL From 595b2661c65efb4135b46ef42f2b6bd9a5d183f0 Mon Sep 17 00:00:00 2001 From: David Dight Date: Mon, 26 Aug 2024 07:10:10 +1000 Subject: [PATCH 167/235] updated --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d2fdfd4..91e52b9 100644 --- a/README.md +++ b/README.md @@ -1590,9 +1590,9 @@ _output_ ### iv. Which enum limit approach to use Compilation times increase with the number of enums that use `conjure_enum` in any compilation unit. -- For a simple project with few enums, there is probably no need to set any limits. -- Where the enum is defined elsewhere (say if you are using `std::errc`) then use `enum_range` or one of the convenience macros -- Where you have defined the enum yourself and it is a scoped enum, use `T::ce_first` and `T::ce_last` +1. For a simple project with few enums, there is probably no need to set any limits. +1. Where the enum is defined elsewhere (say if you are using `std::errc`) then use `enum_range` or one of the convenience macros +1. Where you have defined the enum yourself and it is a scoped enum, use `T::ce_first` and `T::ce_last`, or 2. ## b) Choosing the minimal build ```c++ From bbbde93b4f80e549366160137f90a07e8b735bff Mon Sep 17 00:00:00 2001 From: David Dight Date: Mon, 26 Aug 2024 07:11:41 +1000 Subject: [PATCH 168/235] updated --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 91e52b9..b7ebcc1 100644 --- a/README.md +++ b/README.md @@ -1592,6 +1592,7 @@ _output_ Compilation times increase with the number of enums that use `conjure_enum` in any compilation unit. 1. For a simple project with few enums, there is probably no need to set any limits. 1. Where the enum is defined elsewhere (say if you are using `std::errc`) then use `enum_range` or one of the convenience macros +1. Where the enum is unscoped then use `enum_range` or one of the convenience macros 1. Where you have defined the enum yourself and it is a scoped enum, use `T::ce_first` and `T::ce_last`, or 2. ## b) Choosing the minimal build From aa9e11a3e557cf5438e9bb63e3fe905cfc4643db Mon Sep 17 00:00:00 2001 From: David Dight Date: Mon, 26 Aug 2024 07:32:29 +1000 Subject: [PATCH 169/235] updated --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b7ebcc1..531db60 100644 --- a/README.md +++ b/README.md @@ -1548,7 +1548,7 @@ static_assert(conjure_enum::get_enum_min_value() == 0); static_assert(conjure_enum::get_enum_max_value() == 7); ``` #### ii.a `FIX8_CONJURE_ENUM_SET_RANGE_INTS`, `FIX8_CONJURE_ENUM_SET_RANGE` -For convenience, two macros are provided to make it easier to set custom ranges. +For convenience, two macros are provided to make it easier to set custom ranges using `enum_range`. ```c++ #define FIX8_CONJURE_ENUM_SET_RANGE_INTS(ec,min_int,max_int)... #define FIX8_CONJURE_ENUM_SET_RANGE(min_enum,max_enum)... @@ -1590,9 +1590,9 @@ _output_ ### iv. Which enum limit approach to use Compilation times increase with the number of enums that use `conjure_enum` in any compilation unit. -1. For a simple project with few enums, there is probably no need to set any limits. -1. Where the enum is defined elsewhere (say if you are using `std::errc`) then use `enum_range` or one of the convenience macros -1. Where the enum is unscoped then use `enum_range` or one of the convenience macros +1. For a simple project with few enums, there is probably no need to set any limits; +1. Where the enum is defined elsewhere (say if you are using `std::errc`) then use `enum_range` or one of the convenience macros; +1. Where the enum is unscoped then use `enum_range` or one of the convenience macros; 1. Where you have defined the enum yourself and it is a scoped enum, use `T::ce_first` and `T::ce_last`, or 2. ## b) Choosing the minimal build From 7740c1071ec55b37f4934e3730d39ed48fce0ed4 Mon Sep 17 00:00:00 2001 From: David Dight Date: Tue, 27 Aug 2024 07:03:40 +1000 Subject: [PATCH 170/235] updated --- README.md | 52 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 531db60..62ee121 100644 --- a/README.md +++ b/README.md @@ -1002,6 +1002,17 @@ _output_ ```CSV exception: twenty ``` +You can also create an `enum_bitset` from a `std::bitset` of the same number of bits. +```c++ +std::bitset<10> bs{1 << 1 | 1 << 3 | 1 << 6}; +enum_bitset ed(bs); +std::cout << ed << '\n'; +``` +_output_ +```CSV +0001001010 +``` + ## b) Standard bit operators All of the standard operators are supported. Assignment operators return a `enum_bitset&`, non-assignment operators return a `enum_bitset`. @@ -1109,7 +1120,23 @@ _output_ 0001001111 ``` -### ii. `std::ostream& operator<<`, `to_string` +### ii. `operator std::bitset()` +```c++ +constexpr operator std::bitset() const; +``` +Cast an `enum_bitset` to a `std::bitset` with the same number of bits. + +```c++ +enum_bitset ec(numbers::one,numbers::three,numbers::six); +std::bitset<10> bs{ec}; +std::cout << bs << '\n'; +``` +_output_ +```CSV +0001001010 +``` + +### iii. `std::ostream& operator<<`, `to_string` ```c++ friend constexpr std::ostream& operator<<(std::ostream& os, const enum_bitset& what); constexpr std::string to_string(char zero='0', char one='1') const; @@ -1127,7 +1154,7 @@ _output_ 0001001010 ---+--+-+- ``` -### iii. `for_each`, `for_each_n` +### iv. `for_each`, `for_each_n` ```c++ template requires std::invocable @@ -1187,7 +1214,7 @@ numbers::two numbers::five ``` -### iv. Using `conjure_enum::dispatch` with `enum_bitset` +### v. Using `conjure_enum::dispatch` with `enum_bitset` Using an `enum_bitset` wth `conjure_enum::dispatch` can be a convenient way of iterating through a set of bits to call specific functions using `for_each`. The following demonstrates this: ```c++ const auto dd3 @@ -1217,6 +1244,25 @@ _output_ not found: 5 ``` +### vi. `get_underlying` +```c++ +constexpr U get_underlying() const; +``` +Returns the underlying integral bitset object. + +### vii. `get_underlying_bit_size` +```c++ +constexpr int get_underlying_bit_size() const +``` +Returns the number of bits that the underlying integral contains. Will always be a power of 2. The number of bits may be larger +than the count of bits. + +### viii. `get_unused_bit_mask` +```c++ +constexpr U get_unused_bit_mask() const; +``` +Returns a bit mask that would mask off the unused bits of the underlying integral. + --- # 5. API and Examples using `conjure_type` `conjure_type` is a general purpose class allowing you to extract a string representation of any typename. From 4f70d6b7a4775e844f8bebb86d13ce24d185b245 Mon Sep 17 00:00:00 2001 From: David Dight Date: Tue, 27 Aug 2024 07:11:28 +1000 Subject: [PATCH 171/235] updated --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 62ee121..f191e8c 100644 --- a/README.md +++ b/README.md @@ -933,6 +933,7 @@ constexpr enum_bitset() = default; constexpr enum_bitset(U bits); constexpr enum_bitset(std::string_view from, bool anyscope=false, char sep='|', bool ignore_errors=true); +constexpr enum_bitset(std::bitset from); template constexpr enum_bitset(E... comp); @@ -1248,20 +1249,20 @@ not found: 5 ```c++ constexpr U get_underlying() const; ``` -Returns the underlying integral bitset object. +Returns the underlying integral value. ### vii. `get_underlying_bit_size` ```c++ constexpr int get_underlying_bit_size() const ``` -Returns the number of bits that the underlying integral contains. Will always be a power of 2. The number of bits may be larger +Returns the number of bits that the underlying integral contains. Will always be a power of 2 and an integral type. The number of bits may be larger than the count of bits. ### viii. `get_unused_bit_mask` ```c++ constexpr U get_unused_bit_mask() const; ``` -Returns a bit mask that would mask off the unused bits of the underlying integral. +Returns a bit mask that would mask off the _used_ bits of the underlying integral. --- # 5. API and Examples using `conjure_type` From d06ca052a289ef16ac4dcb86afb2993131c9e0dd Mon Sep 17 00:00:00 2001 From: David Dight Date: Tue, 27 Aug 2024 07:18:58 +1000 Subject: [PATCH 172/235] updated --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f191e8c..939a8a0 100644 --- a/README.md +++ b/README.md @@ -1615,8 +1615,8 @@ using `ce_first` and `ce_last`. `conjure_enum` will use these values to set the You can set either, both or neither. A range value not set will default to the `FIX8_CONJURE_ENUM_MIN_VALUE` or `FIX8_CONJURE_ENUM_MAX_VALUE`. > [!WARNING] -> With _unscoped_ enums, there can only be one enum type with `T::ce_first` and `T::ce_last` defined in any translation unit (ODR), due to the open scoping of unscoped -> enums. It is therefore recommended to only use this feature with scoped enums. +> With _unscoped_ enums, there can only be one enum type with `ce_first` and `ce_last` defined in any translation unit (ODR). +> It is therefore recommended to only use this feature with scoped enums. For example: ```c++ From ed688641dd75e73843ceee5702a51c8508895888 Mon Sep 17 00:00:00 2001 From: David Dight Date: Tue, 27 Aug 2024 07:27:55 +1000 Subject: [PATCH 173/235] updated --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 939a8a0..dc13580 100644 --- a/README.md +++ b/README.md @@ -1137,23 +1137,30 @@ _output_ 0001001010 ``` -### iii. `std::ostream& operator<<`, `to_string` +### iii. `std::ostream& operator<<`, `to_string`, `to_hex_string` ```c++ friend constexpr std::ostream& operator<<(std::ostream& os, const enum_bitset& what); constexpr std::string to_string(char zero='0', char one='1') const; + +template +constexpr std::string to_hex_string() const; ``` Inserts default string representation into `std::ostream`.
Returns a `std::string` representation of the bitset. Optionally specify which characters to use for `0` and `1`. +Returns a `std::string` representation of the bitset in hex format. Optionally specify `showbase` which will prefix +the string with `0x` or `0X`; optionally specify `uppercase` which will set the case of the hex digits. ```c++ enum_bitset ec(numbers::one,numbers::three,numbers::six); std::cout << ec << '\n'; std::cout << ec.to_string('-', '+') << '\n'; +std::cout << ec.to_hex_string() << '\n'; ``` _output_ ```CSV 0001001010 ---+--+-+- +0X4A ``` ### iv. `for_each`, `for_each_n` ```c++ From 9658f31f9906ed175b1f1a68db930c16fc79e6e0 Mon Sep 17 00:00:00 2001 From: David Dight Date: Tue, 27 Aug 2024 11:27:39 +1000 Subject: [PATCH 174/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dc13580..11a892e 100644 --- a/README.md +++ b/README.md @@ -1146,7 +1146,7 @@ template constexpr std::string to_hex_string() const; ``` Inserts default string representation into `std::ostream`.
-Returns a `std::string` representation of the bitset. Optionally specify which characters to use for `0` and `1`. +Returns a `std::string` representation of the bitset. Optionally specify which characters to use for `0` and `1`.
Returns a `std::string` representation of the bitset in hex format. Optionally specify `showbase` which will prefix the string with `0x` or `0X`; optionally specify `uppercase` which will set the case of the hex digits. From 85c82f621352b76a867fe6ab3b44e55e5f052a06 Mon Sep 17 00:00:00 2001 From: David Dight Date: Tue, 27 Aug 2024 11:27:56 +1000 Subject: [PATCH 175/235] pre-rel 1.1e --- include/fix8/conjure_enum.hpp | 16 +++++++-- include/fix8/conjure_enum_bitset.hpp | 48 +++++++++++++++++++++++-- utests/unittests.cpp | 54 ++++++++++++++++++++++++++-- 3 files changed, 111 insertions(+), 7 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 78b10b1..3e196b5 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -168,11 +168,21 @@ concept valid_enum = requires(T) //----------------------------------------------------------------------------------------- // You can specialise this class to define a custom range for your enum +// Alternatively, alias T::ce_first as the first and T::ce_last as the last enum in +// your enum declaration //----------------------------------------------------------------------------------------- -template -struct enum_range final : public static_only +template +class enum_range final : public static_only { - static constexpr int min{FIX8_CONJURE_ENUM_MIN_VALUE}, max{FIX8_CONJURE_ENUM_MAX_VALUE}; + static constexpr int get_first() noexcept requires std::is_enum_v + { return static_cast(T::ce_first); } + static constexpr int get_last() noexcept requires std::is_enum_v + { return static_cast(T::ce_last); } + static constexpr int get_first() noexcept { return FIX8_CONJURE_ENUM_MIN_VALUE; } + static constexpr int get_last() noexcept { return FIX8_CONJURE_ENUM_MAX_VALUE; }; + +public: + static constexpr int min{get_first()}, max{get_last()}; }; //----------------------------------------------------------------------------------------- diff --git a/include/fix8/conjure_enum_bitset.hpp b/include/fix8/conjure_enum_bitset.hpp index 71a2b5a..67201bc 100644 --- a/include/fix8/conjure_enum_bitset.hpp +++ b/include/fix8/conjure_enum_bitset.hpp @@ -41,6 +41,11 @@ #include #include #include +#if __has_include() +# include +#else +#include +#endif #include //----------------------------------------------------------------------------------------- @@ -100,12 +105,17 @@ class enum_bitset static constexpr U all_bits { (1 << countof) - 1 }; U _present{}; +#if __has_include() + static constexpr std::array _hexfmtarr { "{:#x}", "{:#X}", "{:x}", "{:#X}" }; +#endif + public: using enum_bitset_underlying_type = U; using reference = _reference; using const_reference = _reference; explicit constexpr enum_bitset(U bits) noexcept : _present(bits) {} + explicit constexpr enum_bitset(std::bitset from) : _present(from.to_ullong()) {} constexpr enum_bitset(std::string_view from, bool anyscope=false, char sep='|', bool ignore_errors=true) : _present(factory(from, anyscope, sep, ignore_errors)) {} @@ -124,8 +134,21 @@ class enum_bitset { return std::popcount(static_cast>(_present)); } // C++23: upgrade to std::bitset when count is constexpr constexpr std::size_t not_count() const noexcept { return countof - count(); } constexpr std::size_t size() const noexcept { return countof; } - constexpr unsigned long to_ulong() const noexcept { return _present; } - constexpr unsigned long long to_ullong() const noexcept { return _present; } + constexpr unsigned long to_ulong() const + { + if (std::bit_width(_present) > 32) + throw std::overflow_error("overflow"); + return _present; + } + constexpr unsigned long long to_ullong() const + { + if constexpr (countof > 64) + throw std::overflow_error("overflow"); + return _present; + } + constexpr U get_underlying() const noexcept { return _present; } + constexpr int get_underlying_bit_size() const noexcept { return 8 * sizeof(U); } + constexpr U get_unused_bit_mask() const noexcept { return ((1 << get_underlying_bit_size()) - 1) ^ all_bits; } // subscript constexpr auto operator[](U pos) noexcept { return reference(*this, pos); } @@ -247,6 +270,8 @@ class enum_bitset constexpr enum_bitset operator^(T other) const noexcept { return enum_bitset(_present ^ 1 << to_underlying(other)); } constexpr enum_bitset operator~() const noexcept { return enum_bitset(~_present & all_bits); } + constexpr operator auto() const noexcept { return std::bitset(_present); } + /// for_each, for_each_n template requires std::invocable @@ -320,6 +345,25 @@ class enum_bitset return std::bitset(_present).to_string(zero, one); } + template +#if __has_include() + constexpr std::string to_hex_string() const noexcept + { + return std::format(_hexfmtarr[(showbase ? 0 : 2) + (uppercase ? 1 : 0)], _present); + } +#else + std::string to_hex_string() const noexcept + { + std::ostringstream ostr; + if (showbase) + ostr << std::showbase; + if (uppercase) + ostr << std::uppercase; + ostr << std::hex << _present; + return ostr.str(); + } +#endif + friend constexpr std::ostream& operator<<(std::ostream& os, const enum_bitset& what) noexcept { return os << what.to_string(); diff --git a/utests/unittests.cpp b/utests/unittests.cpp index 64015f2..98b7082 100644 --- a/utests/unittests.cpp +++ b/utests/unittests.cpp @@ -50,6 +50,24 @@ enum class directions { left, right, up, down, forward, backward, notfound=-1 }; enum class range_test { first, second, third, fourth, fifth, sixth, seventh, eighth }; enum class range_test1 { first, second, third, fourth, fifth, sixth, seventh, eighth }; enum class range_test2 { first, second, third, fourth, fifth, sixth, seventh, eighth }; +enum class range_test3 { first, second, third, fourth, fifth, sixth, seventh, eighth, ce_first=first, ce_last=eighth }; +enum range_test4 { first, second, third, fourth, fifth, sixth, seventh, eighth, ce_first=first, ce_last=eighth }; +enum class numbers64 : uint64_t +{ + zero, one, two, three, four, + five, six, seven, eight, nine, + ten, eleven, twelve, thirteen, fourteen, + fifteen, sixteen, seventeen, eighteen, nineteen, + twenty, twenty_one, twenty_two, twenty_three, twenty_four, + twenty_five, twenty_six, twenty_seven, twenty_eight, twenty_nine, + thirty, thirty_one, thirty_two, thirty_three, thirty_four, + thirty_five, thirty_six, thirty_seven, thirty_eight, thirty_nine, + forty, forty_one, forty_two, forty_three, forty_four, + forty_five, forty_six, forty_seven, forty_eight, forty_nine, + fifty, fifty_one, fifty_two, fifty_three, fifty_four, + fifty_five, fifty_six, fifty_seven, fifty_eight, fifty_nine, + sixty, sixty_one, sixty_two, sixty_three +}; //----------------------------------------------------------------------------------------- // run as: ctest --output-on-failure @@ -98,6 +116,17 @@ TEST_CASE("custom range") REQUIRE(conjure_enum::get_enum_max_value() == 7); } +//----------------------------------------------------------------------------------------- +TEST_CASE("custom range (alias)") +{ + REQUIRE(conjure_enum::get_enum_min_value() == 0); + REQUIRE(conjure_enum::get_enum_max_value() == 7); + REQUIRE(conjure_enum::get_enum_min_value() == conjure_enum::get_actual_enum_min_value()); + REQUIRE(conjure_enum::get_enum_max_value() == conjure_enum::get_actual_enum_max_value()); + REQUIRE(conjure_enum::get_enum_min_value() == 0); + REQUIRE(conjure_enum::get_enum_max_value() == 7); +} + //----------------------------------------------------------------------------------------- TEST_CASE("is_valid") { @@ -610,6 +639,9 @@ TEST_CASE("enum_bitset") REQUIRE(ec.to_ulong() == 0b0001001010); REQUIRE(ec.to_string('-', '+') == "---+--+-+-"s); REQUIRE(enum_bitset(0b0101001010).to_string() == "0101001010"s); + REQUIRE(ec.to_hex_string<>() == "0x4a"s); + REQUIRE(ec.to_hex_string() == "4a"s); + REQUIRE(ec.to_hex_string() == "0X4A"s); REQUIRE(ec.test()); ec.flip(); @@ -630,6 +662,19 @@ TEST_CASE("enum_bitset") ec.set(numbers::three, false); REQUIRE(ec.test() == false); REQUIRE(ec.any()); + REQUIRE(enum_bitset().get_underlying_bit_size() == 8); + REQUIRE(ec.get_underlying_bit_size() == 16); + REQUIRE(ec.get_unused_bit_mask() == 0b111111 << 10); +} + +//----------------------------------------------------------------------------------------- +TEST_CASE("enum_bitset <==> std::bitset") +{ + std::bitset<10> bs{1 << 1 | 1 << 3 | 1 << 6}; + enum_bitset ed(bs); + REQUIRE(ed.to_ulong() == (1 << 1 | 1 << 3 | 1 << 6)); + std::bitset<10> bs1{ed}; + REQUIRE(bs1.to_ulong() == (1 << 1 | 1 << 3 | 1 << 6)); } //----------------------------------------------------------------------------------------- @@ -685,13 +730,18 @@ TEST_CASE("enum_bitset ext ops") REQUIRE(ee.not_count() == 10 - 2); } +//----------------------------------------------------------------------------------------- +TEST_CASE("enum_bitset::to_ulong overflow") +{ + REQUIRE_NOTHROW(enum_bitset(0b1111111111111).to_ulong()); + REQUIRE_THROWS_AS(enum_bitset(0xfffffffffffffffe).to_ulong(), std::overflow_error); +} + //----------------------------------------------------------------------------------------- TEST_CASE("enum_bitset(std::string_view)") { REQUIRE_THROWS_MATCHES(enum_bitset("zero,twenty,two,three", true, ',', false), std::invalid_argument, Catch::Matchers::Message("twenty")); - enum_bitset sc("zero,two,three", true, ','); - REQUIRE(sc.to_ulong() == 0b1101); } //----------------------------------------------------------------------------------------- From a5caa0c80f8e1d8765377d8c6b9fcba49c862a95 Mon Sep 17 00:00:00 2001 From: David Dight Date: Tue, 27 Aug 2024 15:52:49 +1000 Subject: [PATCH 176/235] updated --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 11a892e..ceef31d 100644 --- a/README.md +++ b/README.md @@ -1265,10 +1265,12 @@ constexpr int get_underlying_bit_size() const Returns the number of bits that the underlying integral contains. Will always be a power of 2 and an integral type. The number of bits may be larger than the count of bits. -### viii. `get_unused_bit_mask` +### viii. `get_bit_mask`,`get_unused_bit_mask` ```c++ +constexpr U get_bit_mask() const; constexpr U get_unused_bit_mask() const; ``` +Returns a bit mask that would mask off the _unused_ bits of the underlying integral. Returns a bit mask that would mask off the _used_ bits of the underlying integral. --- From 1316bc0587fb19302b728d38061d1a2f354eca8e Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 28 Aug 2024 06:26:16 +1000 Subject: [PATCH 177/235] updated --- README.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index ceef31d..daeac0e 100644 --- a/README.md +++ b/README.md @@ -1270,7 +1270,7 @@ than the count of bits. constexpr U get_bit_mask() const; constexpr U get_unused_bit_mask() const; ``` -Returns a bit mask that would mask off the _unused_ bits of the underlying integral. +Returns a bit mask that would mask off the _unused_ bits of the underlying integral.
Returns a bit mask that would mask off the _used_ bits of the underlying integral. --- @@ -1558,8 +1558,14 @@ master will not be considered. --- # 8. Notes ## a) enum limits +Compilation times increase with the number of enums that use `conjure_enum` in any compilation unit. +1. For a simple project with few enums, there is probably no need to set any limits; +1. Where the enum is defined elsewhere (say if you are using `std::errc`) then use `enum_range` or one of the convenience macros; +1. Where the enum is unscoped then use `enum_range` or one of the convenience macros; +1. Where you have defined the enum yourself and it is a scoped enum, use `T::ce_first` and `T::ce_last`, or 2. + ### i. `FIX8_CONJURE_ENUM_MIN_VALUE`, `FIX8_CONJURE_ENUM_MAX_VALUE` -These are set by default unless you override them by defining them in your application. They are the global range default for enums using `conjure_enum`. +These are set by default unless you override them by defining them in your application. They are the global range default for all enums using `conjure_enum`. > [!IMPORTANT] > If you want to define these values they must appear _before_ you include `conjure_enum.hpp`. @@ -1644,13 +1650,6 @@ _output_ 0/7 ``` -### iv. Which enum limit approach to use -Compilation times increase with the number of enums that use `conjure_enum` in any compilation unit. -1. For a simple project with few enums, there is probably no need to set any limits; -1. Where the enum is defined elsewhere (say if you are using `std::errc`) then use `enum_range` or one of the convenience macros; -1. Where the enum is unscoped then use `enum_range` or one of the convenience macros; -1. Where you have defined the enum yourself and it is a scoped enum, use `T::ce_first` and `T::ce_last`, or 2. - ## b) Choosing the minimal build ```c++ #define FIX8_CONJURE_ENUM_MINIMAL From 0c60ff6994fcfa5ace06896f1e587261bb077f01 Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 28 Aug 2024 06:34:17 +1000 Subject: [PATCH 178/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index daeac0e..4f2a721 100644 --- a/README.md +++ b/README.md @@ -1978,7 +1978,7 @@ From a compilation performance perspective, `conjure_enum` roughly matches the p | :--- | :--- | :--- | ---: | | [gcc](https://gcc.gnu.org/projects/cxx-status.html) | `11`, `12`, `13`, `14`| `std::format` not complete in `11`, `12` | `<= 10` | | [clang](https://clang.llvm.org/cxx_status.html) | `15`, `16`, `17`, `18`| Catch2 needs `cxx_std_20` in `15` | `<= 14` | -| [msvc](https://learn.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance) | `16`, `17` | Visual Studio 2019,2022, latest `17.11.1`| `<= 16.9`| +| [msvc](https://learn.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance) | `16`, `17` | Visual Studio 2019,2022, latest `17.11.2`| `<= 16.9`| | [xcode](https://developer.apple.com/support/xcode/) | `15` | Apple LLVM 15.0.0, some issues with `constexpr`, workarounds| `<= 14`| # 11. Compiler issues From 8809fb2e31f7971682027f6fb169a9a5d7de7fe2 Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 28 Aug 2024 06:34:23 +1000 Subject: [PATCH 179/235] pre-rel 1.1e --- include/fix8/conjure_enum_bitset.hpp | 8 ++------ utests/unittests.cpp | 1 + 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/include/fix8/conjure_enum_bitset.hpp b/include/fix8/conjure_enum_bitset.hpp index 67201bc..3f721c1 100644 --- a/include/fix8/conjure_enum_bitset.hpp +++ b/include/fix8/conjure_enum_bitset.hpp @@ -140,14 +140,10 @@ class enum_bitset throw std::overflow_error("overflow"); return _present; } - constexpr unsigned long long to_ullong() const - { - if constexpr (countof > 64) - throw std::overflow_error("overflow"); - return _present; - } + constexpr unsigned long long to_ullong() const noexcept { return _present; } constexpr U get_underlying() const noexcept { return _present; } constexpr int get_underlying_bit_size() const noexcept { return 8 * sizeof(U); } + constexpr U get_bit_mask() const noexcept { return all_bits; } constexpr U get_unused_bit_mask() const noexcept { return ((1 << get_underlying_bit_size()) - 1) ^ all_bits; } // subscript diff --git a/utests/unittests.cpp b/utests/unittests.cpp index 98b7082..d7ba7fa 100644 --- a/utests/unittests.cpp +++ b/utests/unittests.cpp @@ -665,6 +665,7 @@ TEST_CASE("enum_bitset") REQUIRE(enum_bitset().get_underlying_bit_size() == 8); REQUIRE(ec.get_underlying_bit_size() == 16); REQUIRE(ec.get_unused_bit_mask() == 0b111111 << 10); + REQUIRE(ec.get_bit_mask() == 0b1111111111); } //----------------------------------------------------------------------------------------- From 2adeffb7f7beb1f4a2244c23aaa1714c3b737baf Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 28 Aug 2024 06:37:22 +1000 Subject: [PATCH 180/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4f2a721..544e043 100644 --- a/README.md +++ b/README.md @@ -1588,6 +1588,7 @@ These definitions set the minimum and maximum enum values that are supported. Yo > If you wish to set ranges on a per enum basis, use `enum_range` (see below). ### ii. using `enum_range` +You can specialise this class to override the defaults and set your own range on a per enum basis. ```c++ template struct enum_range @@ -1598,7 +1599,6 @@ struct enum_range The `min` and `max` values are used to set the range of enum values for enums in `conjure_enum`. As shown above, the default values will be `FIX8_CONJURE_ENUM_MIN_VALUE` and `FIX8_CONJURE_ENUM_MAX_VALUE`. -You can specialise this class to override the defaults and set your own range on a per enum basis: ```c++ enum class range_test { first, second, third, fourth, fifth, sixth, seventh, eighth }; template<> From df01413568a9de39ddffe38e1e995476a1edbddb Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 28 Aug 2024 10:33:08 +1000 Subject: [PATCH 181/235] updated --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 544e043..e06b16d 100644 --- a/README.md +++ b/README.md @@ -1144,6 +1144,7 @@ constexpr std::string to_string(char zero='0', char one='1') const; template constexpr std::string to_hex_string() const; +constexpr std::string to_hex_string() const; ``` Inserts default string representation into `std::ostream`.
Returns a `std::string` representation of the bitset. Optionally specify which characters to use for `0` and `1`.
From 7017bdba2736ddd8f208e1e0d63022cca37dd609 Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 28 Aug 2024 10:33:14 +1000 Subject: [PATCH 182/235] pre-rel 1.1e --- include/fix8/conjure_enum_bitset.hpp | 5 +---- include/fix8/conjure_type.hpp | 4 ---- utests/unittests.cpp | 2 +- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/include/fix8/conjure_enum_bitset.hpp b/include/fix8/conjure_enum_bitset.hpp index 3f721c1..e7abaef 100644 --- a/include/fix8/conjure_enum_bitset.hpp +++ b/include/fix8/conjure_enum_bitset.hpp @@ -8,10 +8,6 @@ // see https://github.com/fix8mt/conjure_enum // // Lightweight header-only C++20 enum and typename reflection -// -// Parts based on magic_enum -// Copyright (c) 2019 - 2024 Daniil Goncharov . -// // Licensed under the MIT License . // // Permission is hereby granted, free of charge, to any person obtaining a copy @@ -359,6 +355,7 @@ class enum_bitset return ostr.str(); } #endif + constexpr std::string to_hex_string() const noexcept { return to_hex_string<>(); } friend constexpr std::ostream& operator<<(std::ostream& os, const enum_bitset& what) noexcept { diff --git a/include/fix8/conjure_type.hpp b/include/fix8/conjure_type.hpp index e12b06a..c19b9cb 100644 --- a/include/fix8/conjure_type.hpp +++ b/include/fix8/conjure_type.hpp @@ -8,10 +8,6 @@ // see https://github.com/fix8mt/conjure_enum // // Lightweight header-only C++20 enum and typename reflection -// -// Parts based on magic_enum -// Copyright (c) 2019 - 2024 Daniil Goncharov . -// // Licensed under the MIT License . // // Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/utests/unittests.cpp b/utests/unittests.cpp index d7ba7fa..186d4d6 100644 --- a/utests/unittests.cpp +++ b/utests/unittests.cpp @@ -639,7 +639,7 @@ TEST_CASE("enum_bitset") REQUIRE(ec.to_ulong() == 0b0001001010); REQUIRE(ec.to_string('-', '+') == "---+--+-+-"s); REQUIRE(enum_bitset(0b0101001010).to_string() == "0101001010"s); - REQUIRE(ec.to_hex_string<>() == "0x4a"s); + REQUIRE(ec.to_hex_string() == "0x4a"s); REQUIRE(ec.to_hex_string() == "4a"s); REQUIRE(ec.to_hex_string() == "0X4A"s); From 7d5daef634ab96aa7a34bbef1a39679ab247b31b Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 28 Aug 2024 10:57:54 +1000 Subject: [PATCH 183/235] updated --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index e06b16d..4d5fedf 100644 --- a/README.md +++ b/README.md @@ -45,10 +45,10 @@ ||**Link**|**Description**| --|--|-- |1|[Implementation](include/fix8/conjure_enum.hpp)| For header implementation| -|2|[`conjure_enum` API and Examples](#3-api-and-examples-using-conjure_enum)| General examples| -|3|[`enum_bitset` API and Examples](#4-api-and-examples-using-enum_bitset)| Enhanced enum aware `std::bitset`| -|4|[`conjure_type` API and Examples](#5-api-and-examples-using-conjure_type)| Any type string extractor| -|5|[`fixed_string` API](#6-api-for-fixed_string)| Statically stored fixed string| +|2|[`conjure_enum`](#3-conjure_enum)| General examples| +|3|[`enum_bitset`](#4-using-enum_bitset)| Enhanced enum aware `std::bitset`| +|4|[`conjure_type`](#5-conjure_type)| Any type string extractor| +|5|[`fixed_string`](#6-fixed_string)| Statically stored fixed string| |6|[Building](#7-building)| How to build or include| |7|[vcpkg](https://vcpkg.io/en/package/conjure-enum)| For vcpkg package| |8|[Notes](#8-notes)| Notes on the implementation, limits, etc| @@ -61,7 +61,7 @@ > Even better in [full read view](./README.md) of this page. > > For the latest cutting edge changes, see the [dev branch](https://github.com/fix8mt/conjure_enum/tree/dev). -> You can view the changes [here](https://github.com/fix8mt/conjure_enum/compare/master..dev). +> You can view the changes (if any) [here](https://github.com/fix8mt/conjure_enum/compare/master..dev). --- # 2. Introduction @@ -102,7 +102,7 @@ unlocked the potential of [`constexpr` algorithms](https://www.open-std.org/jtc1 - ***Transparency***: Compiler implementation variability fully documented, verifiable and reportable (see 12 above) --- -# 3. API and Examples using `conjure_enum` +# 3. `conjure_enum` All examples refer to the following enums: ```c++ enum class component { scheme, authority, userinfo, user, password, host, port, path=12, test=path, query, fragment }; @@ -899,7 +899,7 @@ false ``` --- -# 4. API and Examples using `enum_bitset` +# 4. `enum_bitset` `enum_bitset` is a convenient way of creating bitsets based on `std::bitset`. It uses your enum (scoped or unscoped) for the bit positions (and names). > [!NOTE] @@ -1275,7 +1275,7 @@ Returns a bit mask that would mask off the _unused_ bits of the underlying integ Returns a bit mask that would mask off the _used_ bits of the underlying integral. --- -# 5. API and Examples using `conjure_type` +# 5. `conjure_type` `conjure_type` is a general purpose class allowing you to extract a string representation of any typename. The string will be stored statically by the compiler, so you can use the statically generated value `name` to obtain your type. > [!IMPORTANT] @@ -1369,7 +1369,7 @@ static consteval const char* FIX8::conjure_type::tpeek() [with T = test] ``` --- -# 6. API for `fixed_string` +# 6. `fixed_string` `fixed_string` is a specialisation of `std::array` that provides statics storage for an ASCII zero (asciiz) string. The purpose of this class is to allow the creation of `constexpr` strings with specfic storage, adding a trailing `0`. It is used by `conjure_enum` to store all strings. API is described below. Other uses of this class are possible. From 5aa524e2ee540c09b3fd72dcdb92fb69db69df22 Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 28 Aug 2024 11:09:10 +1000 Subject: [PATCH 184/235] updated --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4d5fedf..2ee0b21 100644 --- a/README.md +++ b/README.md @@ -45,10 +45,10 @@ ||**Link**|**Description**| --|--|-- |1|[Implementation](include/fix8/conjure_enum.hpp)| For header implementation| -|2|[`conjure_enum`](#3-conjure_enum)| General examples| +|2|[`conjure_enum`](#3-conjure_enum)| API and examples| |3|[`enum_bitset`](#4-using-enum_bitset)| Enhanced enum aware `std::bitset`| |4|[`conjure_type`](#5-conjure_type)| Any type string extractor| -|5|[`fixed_string`](#6-fixed_string)| Statically stored fixed string| +|5|[`fixed_string`](#6-fixed_string)| Statically stored null terminated fixed string| |6|[Building](#7-building)| How to build or include| |7|[vcpkg](https://vcpkg.io/en/package/conjure-enum)| For vcpkg package| |8|[Notes](#8-notes)| Notes on the implementation, limits, etc| From 1f6fa881c037a14e4a73256c550031df47982fe8 Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 28 Aug 2024 11:10:12 +1000 Subject: [PATCH 185/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2ee0b21..2b96234 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ --|--|-- |1|[Implementation](include/fix8/conjure_enum.hpp)| For header implementation| |2|[`conjure_enum`](#3-conjure_enum)| API and examples| -|3|[`enum_bitset`](#4-using-enum_bitset)| Enhanced enum aware `std::bitset`| +|3|[`enum_bitset`](#4-enum_bitset)| Enhanced enum aware `std::bitset`| |4|[`conjure_type`](#5-conjure_type)| Any type string extractor| |5|[`fixed_string`](#6-fixed_string)| Statically stored null terminated fixed string| |6|[Building](#7-building)| How to build or include| From ea9c880c394bb816ea714c40a014a3c7354f71c2 Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 28 Aug 2024 14:16:10 +1000 Subject: [PATCH 186/235] updated --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 2b96234..2b4b1ea 100644 --- a/README.md +++ b/README.md @@ -906,9 +906,8 @@ for the bit positions (and names). > - Your enum sequence _must_ be 0 based > - Continuous > - The last value must be less than the count of enumerations -> - This implementation is limited to 64 bits -> > We decided on these restrictions for both simplicity and practicality - bitsets only really make sense when represented in this manner. +> - this implementation is limited to 64 bits > [!IMPORTANT] > You must include From 4f985d81f948936e71aa7f137c11cfba3929f2c3 Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 28 Aug 2024 14:16:44 +1000 Subject: [PATCH 187/235] updated --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2b4b1ea..924ba6a 100644 --- a/README.md +++ b/README.md @@ -906,8 +906,10 @@ for the bit positions (and names). > - Your enum sequence _must_ be 0 based > - Continuous > - The last value must be less than the count of enumerations +> > We decided on these restrictions for both simplicity and practicality - bitsets only really make sense when represented in this manner. -> - this implementation is limited to 64 bits +> +> - This implementation is limited to 64 bits > [!IMPORTANT] > You must include From a4ef5002884566ee3724874395e4f85b046944cc Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 28 Aug 2024 14:18:49 +1000 Subject: [PATCH 188/235] updated --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 924ba6a..4248e08 100644 --- a/README.md +++ b/README.md @@ -907,7 +907,7 @@ for the bit positions (and names). > - Continuous > - The last value must be less than the count of enumerations > -> We decided on these restrictions for both simplicity and practicality - bitsets only really make sense when represented in this manner. +> We decided on these restrictions for both simplicity and practicality - bitsets only really make sense when represented in this manner; also... > > - This implementation is limited to 64 bits @@ -1145,6 +1145,7 @@ constexpr std::string to_string(char zero='0', char one='1') const; template constexpr std::string to_hex_string() const; + constexpr std::string to_hex_string() const; ``` Inserts default string representation into `std::ostream`.
@@ -1156,12 +1157,14 @@ the string with `0x` or `0X`; optionally specify `uppercase` which will set the enum_bitset ec(numbers::one,numbers::three,numbers::six); std::cout << ec << '\n'; std::cout << ec.to_string('-', '+') << '\n'; +std::cout << ec.to_hex_string() << '\n'; std::cout << ec.to_hex_string() << '\n'; ``` _output_ ```CSV 0001001010 ---+--+-+- +0x4a 0X4A ``` ### iv. `for_each`, `for_each_n` From 606b80a27603ae7521315b1d76e6259ef325373d Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 28 Aug 2024 17:53:49 +1000 Subject: [PATCH 189/235] updated --- README.md | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 4248e08..ba417d1 100644 --- a/README.md +++ b/README.md @@ -44,18 +44,17 @@ # 1. Quick links ||**Link**|**Description**| --|--|-- -|1|[Implementation](include/fix8/conjure_enum.hpp)| For header implementation| -|2|[`conjure_enum`](#3-conjure_enum)| API and examples| -|3|[`enum_bitset`](#4-enum_bitset)| Enhanced enum aware `std::bitset`| -|4|[`conjure_type`](#5-conjure_type)| Any type string extractor| -|5|[`fixed_string`](#6-fixed_string)| Statically stored null terminated fixed string| -|6|[Building](#7-building)| How to build or include| -|7|[vcpkg](https://vcpkg.io/en/package/conjure-enum)| For vcpkg package| -|8|[Notes](#8-notes)| Notes on the implementation, limits, etc| -|9|[Benchmarks](#9-benchmarks)| Benchmarking | -|10|[Compilers](#10-compiler-support)| Supported compilers| -|11|[Compiler issues](#11-compiler-issues)| Workarounds for various compiler issues| -|12|[Results of `std::source_location`](reference/source_location.md)| For implementation specific `std::source_location` results| +|1|[`conjure_enum`](#3-conjure_enum)| API and examples| +|2|[`enum_bitset`](#4-enum_bitset)| Enhanced enum aware `std::bitset`| +|3|[`conjure_type`](#5-conjure_type)| Any type string extractor| +|4|[`fixed_string`](#6-fixed_string)| Statically stored null terminated fixed string| +|5|[Building](#7-building)| How to build or include| +|6|[vcpkg](https://vcpkg.io/en/package/conjure-enum)| For vcpkg package| +|7|[Notes](#8-notes)| Notes on the implementation, limits, etc| +|8|[Benchmarks](#9-benchmarks)| Benchmarking | +|9|[Compilers](#10-compiler-support)| Supported compilers| +|10|[Compiler issues](#11-compiler-issues)| Workarounds for various compiler issues| +|11|[Results of `std::source_location`](reference/source_location.md)| For implementation specific `std::source_location` results| > [!TIP] > Use the built-in [table of contents](https://github.blog/changelog/2021-04-13-table-of-contents-support-in-markdown-files/) to navigate this guide. > Even better in [full read view](./README.md) of this page. From 6801ffa73f9dbd01ee833ea2480b36469590c270 Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 28 Aug 2024 17:55:32 +1000 Subject: [PATCH 190/235] updated --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index ba417d1..9ca690b 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,6 @@ # 1. Quick links -||**Link**|**Description**| --|--|-- |1|[`conjure_enum`](#3-conjure_enum)| API and examples| |2|[`enum_bitset`](#4-enum_bitset)| Enhanced enum aware `std::bitset`| From ffbc8c67d14461fcce538db80b29dd1406928937 Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 28 Aug 2024 17:56:54 +1000 Subject: [PATCH 191/235] updated --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9ca690b..1d73d88 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ # 1. Quick links +|||| --|--|-- |1|[`conjure_enum`](#3-conjure_enum)| API and examples| |2|[`enum_bitset`](#4-enum_bitset)| Enhanced enum aware `std::bitset`| From 4c1430812f7f2d3d62a191862a6c76b8eb7f7f0f Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 28 Aug 2024 17:57:34 +1000 Subject: [PATCH 192/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1d73d88..b3660f5 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ # 1. Quick links |||| ---|--|-- +|--|--|--| |1|[`conjure_enum`](#3-conjure_enum)| API and examples| |2|[`enum_bitset`](#4-enum_bitset)| Enhanced enum aware `std::bitset`| |3|[`conjure_type`](#5-conjure_type)| Any type string extractor| From 8470d5f711ab548fa0c6ebed249a432ef1196d10 Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 28 Aug 2024 17:59:57 +1000 Subject: [PATCH 193/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b3660f5..acb3c9f 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ # 1. Quick links -|||| +|1|[`conjure_enum`](#3-conjure_enum)| API and examples| |--|--|--| |1|[`conjure_enum`](#3-conjure_enum)| API and examples| |2|[`enum_bitset`](#4-enum_bitset)| Enhanced enum aware `std::bitset`| From baac0702cec9fa4c9e22afe55056690f1efd1242 Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 28 Aug 2024 18:00:57 +1000 Subject: [PATCH 194/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index acb3c9f..4a79c99 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ # 1. Quick links |1|[`conjure_enum`](#3-conjure_enum)| API and examples| -|--|--|--| +|:--|:--|:--| |1|[`conjure_enum`](#3-conjure_enum)| API and examples| |2|[`enum_bitset`](#4-enum_bitset)| Enhanced enum aware `std::bitset`| |3|[`conjure_type`](#5-conjure_type)| Any type string extractor| From 873957aafeb80eb2cb63eae0efaead8f8f62b538 Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 28 Aug 2024 18:01:13 +1000 Subject: [PATCH 195/235] updated --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 4a79c99..ed2b74f 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,6 @@ # 1. Quick links |1|[`conjure_enum`](#3-conjure_enum)| API and examples| |:--|:--|:--| -|1|[`conjure_enum`](#3-conjure_enum)| API and examples| |2|[`enum_bitset`](#4-enum_bitset)| Enhanced enum aware `std::bitset`| |3|[`conjure_type`](#5-conjure_type)| Any type string extractor| |4|[`fixed_string`](#6-fixed_string)| Statically stored null terminated fixed string| From 2ff522bb06ecf0c7d687a668ee836bc9253c6709 Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 28 Aug 2024 18:06:21 +1000 Subject: [PATCH 196/235] updated --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ed2b74f..eef7b89 100644 --- a/README.md +++ b/README.md @@ -669,8 +669,8 @@ _output_ ``` ## q) `is_scoped` ```c++ -struct is_scoped : std::integral_constant>; }>{}; +struct is_scoped : std::bool_constant>; }>{}; ``` Returns `true` if the specified enum type is scoped. ```c++ @@ -907,7 +907,7 @@ for the bit positions (and names). > > We decided on these restrictions for both simplicity and practicality - bitsets only really make sense when represented in this manner; also... > -> - This implementation is limited to 64 bits +> - This implementation is limited to 64 bits (arbitrary length impl. soon). > [!IMPORTANT] > You must include From 43d5f25166f09fd7b9268b07d991fb27083541bf Mon Sep 17 00:00:00 2001 From: David Dight Date: Wed, 28 Aug 2024 18:07:35 +1000 Subject: [PATCH 197/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index eef7b89..1138992 100644 --- a/README.md +++ b/README.md @@ -1373,7 +1373,7 @@ static consteval const char* FIX8::conjure_type::tpeek() [with T = test] --- # 6. `fixed_string` `fixed_string` is a specialisation of `std::array` that provides statics storage for an ASCII zero (asciiz) string. The purpose of this class is to allow the -creation of `constexpr` strings with specfic storage, adding a trailing `0`. It is used by `conjure_enum` to store all strings. API is described below. Other uses of this class are possible. +creation of `constexpr` strings with specfic storage, adding a trailing `0`. It is used by `conjure_enum` to store all strings. API is described below. ## a) Creating a `fixed_string` ```c++ From 960f7c1c718bb974a0f55ebe5c5299cf34c18b63 Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 29 Aug 2024 07:16:31 +1000 Subject: [PATCH 198/235] updated --- README.md | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 1138992..fbffb46 100644 --- a/README.md +++ b/README.md @@ -82,9 +82,9 @@ unlocked the potential of [`constexpr` algorithms](https://www.open-std.org/jtc1 - anonymous and named namespaced enums and types - custom [enum ranges](#ii-using-enum_range) - ***Easy to Use***: Class-based approach with intuitive syntax -- ***Convenient***: `enum_bitset` provides an enhanced enum aware `std::bitset` (see 3 above) -- ***Useful***: `conjure_type` gives you the type string of _any type!_ (see 4 above) -- ***Wide Compiler Compatibility***: Support for: (see 10 above) +- ***Convenient***: `enum_bitset` provides an enhanced enum aware `std::bitset` (see 2 above) +- ***Useful***: `conjure_type` gives you the type string of _any type!_ (see 3 above) +- ***Wide Compiler Compatibility***: Support for: (see 9 above) - GCC - Clang - MSVC @@ -97,7 +97,7 @@ unlocked the potential of [`constexpr` algorithms](https://www.open-std.org/jtc1 - `for_each_n` - `dispatch` - iterators and more! -- ***Transparency***: Compiler implementation variability fully documented, verifiable and reportable (see 12 above) +- ***Transparency***: Compiler implementation variability fully documented, verifiable and reportable (see 11 above) --- # 3. `conjure_enum` @@ -1440,25 +1440,28 @@ cmake .. make -j4 ctest (or make test) ``` +### Windows environments +Create a new console project. Add the repo `https://github.com/fix8mt/conjure_enum.git` and clone the source. +Make sure you set the C++ language to C++20 in the project preferences. The project should build and run the unit tests +by default. + +The package is also available on [vckpg](https://vcpkg.io/en/package/conjure-enum). + +### Default compiler warnings By default all warnings are enabled. To prevent this, pass the following to cmake: ```cmake cmake -DBUILD_ALL_WARNINGS=false .. ``` +### Default unit tests By default the unit tests are built (which will download Catch2). To prevent this, pass the following to cmake: ```cmake cmake -DBUILD_UNITTESTS=false .. ``` +### Default executable stripping To disable stripping of the executables: ```cmake cmake -DBUILD_STRIP_EXE=false .. ``` -### Windows environments -Create a new console project. Add the repo `https://github.com/fix8mt/conjure_enum.git` and clone the source. -Make sure you set the C++ language to C++20 in the project preferences. The project should build and run the unit tests -by default. - -The package is also available on [vckpg](https://vcpkg.io/en/package/conjure-enum). - ## b) Using in your application with cmake In `CMakeLists.txt` set your include path to: ```cmake From c68c601144830a51f22cd19570361a4e857218b2 Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 29 Aug 2024 07:17:46 +1000 Subject: [PATCH 199/235] updated --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index fbffb46..2369f8b 100644 --- a/README.md +++ b/README.md @@ -1429,7 +1429,7 @@ This implementation is header only. Apart from standard C++20 includes there are [Catch2](https://github.com/catchorg/Catch2.git) is used for the built-in unit tests. ## a) Obtaining the source, building the unittests and examples -### \*nix based environments +### i. \*nix based environments To clone and default build the test app, unit tests and the benchmark: ```bash git clone https://github.com/fix8mt/conjure_enum.git @@ -1440,24 +1440,24 @@ cmake .. make -j4 ctest (or make test) ``` -### Windows environments +### ii. Windows environments Create a new console project. Add the repo `https://github.com/fix8mt/conjure_enum.git` and clone the source. Make sure you set the C++ language to C++20 in the project preferences. The project should build and run the unit tests by default. The package is also available on [vckpg](https://vcpkg.io/en/package/conjure-enum). -### Default compiler warnings +### iii. Default compiler warnings By default all warnings are enabled. To prevent this, pass the following to cmake: ```cmake cmake -DBUILD_ALL_WARNINGS=false .. ``` -### Default unit tests +### iv. Default unit tests By default the unit tests are built (which will download Catch2). To prevent this, pass the following to cmake: ```cmake cmake -DBUILD_UNITTESTS=false .. ``` -### Default executable stripping +### v. Default executable stripping To disable stripping of the executables: ```cmake cmake -DBUILD_STRIP_EXE=false .. From d5013fa88e1a12b05caf41d7468e53af6b69046a Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 29 Aug 2024 07:19:39 +1000 Subject: [PATCH 200/235] updated --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 2369f8b..97f75a4 100644 --- a/README.md +++ b/README.md @@ -1462,6 +1462,11 @@ To disable stripping of the executables: ```cmake cmake -DBUILD_STRIP_EXE=false .. ``` +### vi. Default executable stripping +To enable clang compilation profiling: +```CMake +cmake -DBUILD_CLANG_PROFILER=true .. +``` ## b) Using in your application with cmake In `CMakeLists.txt` set your include path to: ```cmake From c498c12814f444d66a51282e119487294d8f93aa Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 29 Aug 2024 07:20:15 +1000 Subject: [PATCH 201/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 97f75a4..8845aa9 100644 --- a/README.md +++ b/README.md @@ -1462,7 +1462,7 @@ To disable stripping of the executables: ```cmake cmake -DBUILD_STRIP_EXE=false .. ``` -### vi. Default executable stripping +### vi. Clang compilation profiling To enable clang compilation profiling: ```CMake cmake -DBUILD_CLANG_PROFILER=true .. From b13a9387e5cc202d290a4f65de5107f9614324a6 Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 29 Aug 2024 07:47:29 +1000 Subject: [PATCH 202/235] pre-rel 1.1e --- include/fix8/conjure_enum.hpp | 6 ++---- include/fix8/conjure_enum_bitset.hpp | 1 + include/fix8/conjure_type.hpp | 1 + utests/edgetests.cpp | 18 ++++++++++-------- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 3e196b5..5903513 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -68,8 +68,6 @@ //----------------------------------------------------------------------------------------- namespace FIX8 { -using namespace std::literals::string_view_literals; - //----------------------------------------------------------------------------------------- // global default enum range //----------------------------------------------------------------------------------------- @@ -196,11 +194,11 @@ class enum_range final : public static_only //----------------------------------------------------------------------------------------- template -class conjure_enum final : public static_only +class conjure_enum : public static_only { static constexpr int enum_min_value{enum_range::min}, enum_max_value{enum_range::max}; static_assert(enum_max_value > enum_min_value, - "FIX8_CONJURE_ENUM_MAX_VALUE (or enum_range::max) must be greater than FIX8_CONJURE_ENUM_MIN_VALUE (or enum_range::min) "); + "FIX8_CONJURE_ENUM_MAX_VALUE, enum_range::max or T::ce_first must be greater than FIX8_CONJURE_ENUM_MIN_VALUE, enum_range::min or T::ce_last) "); public: using enum_tuple = std::tuple; diff --git a/include/fix8/conjure_enum_bitset.hpp b/include/fix8/conjure_enum_bitset.hpp index e7abaef..b632915 100644 --- a/include/fix8/conjure_enum_bitset.hpp +++ b/include/fix8/conjure_enum_bitset.hpp @@ -8,6 +8,7 @@ // see https://github.com/fix8mt/conjure_enum // // Lightweight header-only C++20 enum and typename reflection +// // Licensed under the MIT License . // // Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/include/fix8/conjure_type.hpp b/include/fix8/conjure_type.hpp index c19b9cb..d78a673 100644 --- a/include/fix8/conjure_type.hpp +++ b/include/fix8/conjure_type.hpp @@ -8,6 +8,7 @@ // see https://github.com/fix8mt/conjure_enum // // Lightweight header-only C++20 enum and typename reflection +// // Licensed under the MIT License . // // Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/utests/edgetests.cpp b/utests/edgetests.cpp index fc07f9d..0e7f1ab 100644 --- a/utests/edgetests.cpp +++ b/utests/edgetests.cpp @@ -37,14 +37,16 @@ //----------------------------------------------------------------------------------------- class foobat{}; +#define ENUMS One, Two, Three, Four, Five, Six, Seven, Eight, Nine + namespace { - enum class NineEnums : int { One, Two, Three, Four, Five, Six, Seven, Eight, Nine }; - enum NineEnums1 : int { One, Two, Three, Four, Five, Six, Seven, Eight, Nine }; + enum class NineEnums : int { ENUMS }; + enum NineEnums1 : int { ENUMS }; namespace TEST1 { - enum class NineEnums : int { One, Two, Three, Four, Five, Six, Seven, Eight, Nine }; - enum NineEnums1 : int { One, Two, Three, Four, Five, Six, Seven, Eight, Nine }; + enum class NineEnums : int { ENUMS }; + enum NineEnums1 : int { ENUMS }; class foo{}; } class foo{}; @@ -52,12 +54,12 @@ namespace namespace TEST { - enum class NineEnums : int { One, Two, Three, Four, Five, Six, Seven, Eight, Nine }; - enum NineEnums1 : int { One, Two, Three, Four, Five, Six, Seven, Eight, Nine }; + enum class NineEnums : int { ENUMS }; + enum NineEnums1 : int { ENUMS }; namespace TEST1 { - enum class NineEnums : int { One, Two, Three, Four, Five, Six, Seven, Eight, Nine }; - enum NineEnums1 : int { One, Two, Three, Four, Five, Six, Seven, Eight, Nine }; + enum class NineEnums : int { ENUMS }; + enum NineEnums1 : int { ENUMS }; class foo{}; } class foo{}; From ed4be65c28fb87f0b35ff5a17e46e1af571560a6 Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 29 Aug 2024 08:09:16 +1000 Subject: [PATCH 203/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8845aa9..427bb7e 100644 --- a/README.md +++ b/README.md @@ -1990,7 +1990,7 @@ From a compilation performance perspective, `conjure_enum` roughly matches the p | [gcc](https://gcc.gnu.org/projects/cxx-status.html) | `11`, `12`, `13`, `14`| `std::format` not complete in `11`, `12` | `<= 10` | | [clang](https://clang.llvm.org/cxx_status.html) | `15`, `16`, `17`, `18`| Catch2 needs `cxx_std_20` in `15` | `<= 14` | | [msvc](https://learn.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance) | `16`, `17` | Visual Studio 2019,2022, latest `17.11.2`| `<= 16.9`| -| [xcode](https://developer.apple.com/support/xcode/) | `15` | Apple LLVM 15.0.0, some issues with `constexpr`, workarounds| `<= 14`| +| [xcode](https://developer.apple.com/support/xcode/) | `15` | Apple Xcode Clang 15.0.0 (LLVM 16), some issues with `constexpr`, workarounds| `<= 14`| # 11. Compiler issues | Compiler | Version(s) | Issues | Workaround | From dd5aa17be5c57d88cf318a2c62b223953fe2f209 Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 29 Aug 2024 08:18:02 +1000 Subject: [PATCH 204/235] updated --- README.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 427bb7e..a9e173e 100644 --- a/README.md +++ b/README.md @@ -1429,7 +1429,8 @@ This implementation is header only. Apart from standard C++20 includes there are [Catch2](https://github.com/catchorg/Catch2.git) is used for the built-in unit tests. ## a) Obtaining the source, building the unittests and examples -### i. \*nix based environments +### i. Build platofrm +#### \*nix based environments To clone and default build the test app, unit tests and the benchmark: ```bash git clone https://github.com/fix8mt/conjure_enum.git @@ -1440,31 +1441,31 @@ cmake .. make -j4 ctest (or make test) ``` -### ii. Windows environments +#### Windows environments Create a new console project. Add the repo `https://github.com/fix8mt/conjure_enum.git` and clone the source. Make sure you set the C++ language to C++20 in the project preferences. The project should build and run the unit tests by default. The package is also available on [vckpg](https://vcpkg.io/en/package/conjure-enum). -### iii. Default compiler warnings +### ii. Default compiler warnings By default all warnings are enabled. To prevent this, pass the following to cmake: ```cmake cmake -DBUILD_ALL_WARNINGS=false .. ``` -### iv. Default unit tests +### iii. Default unit tests By default the unit tests are built (which will download Catch2). To prevent this, pass the following to cmake: ```cmake cmake -DBUILD_UNITTESTS=false .. ``` -### v. Default executable stripping +### iv. Default executable stripping To disable stripping of the executables: ```cmake cmake -DBUILD_STRIP_EXE=false .. ``` -### vi. Clang compilation profiling +### v. Clang compilation profiling To enable clang compilation profiling: -```CMake +```cmake cmake -DBUILD_CLANG_PROFILER=true .. ``` ## b) Using in your application with cmake From 3e68d7892f5bd79091241d4e90d8924b69273956 Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 29 Aug 2024 08:20:46 +1000 Subject: [PATCH 205/235] updated --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index a9e173e..45b300e 100644 --- a/README.md +++ b/README.md @@ -1429,10 +1429,10 @@ This implementation is header only. Apart from standard C++20 includes there are [Catch2](https://github.com/catchorg/Catch2.git) is used for the built-in unit tests. ## a) Obtaining the source, building the unittests and examples -### i. Build platofrm +### i. Build platform #### \*nix based environments To clone and default build the test app, unit tests and the benchmark: -```bash +```Shell git clone https://github.com/fix8mt/conjure_enum.git cd conjure_enum mkdir build @@ -1450,27 +1450,27 @@ The package is also available on [vckpg](https://vcpkg.io/en/package/conjure-enu ### ii. Default compiler warnings By default all warnings are enabled. To prevent this, pass the following to cmake: -```cmake +```Shell cmake -DBUILD_ALL_WARNINGS=false .. ``` ### iii. Default unit tests By default the unit tests are built (which will download Catch2). To prevent this, pass the following to cmake: -```cmake +```Shell cmake -DBUILD_UNITTESTS=false .. ``` ### iv. Default executable stripping To disable stripping of the executables: -```cmake +```Shell cmake -DBUILD_STRIP_EXE=false .. ``` ### v. Clang compilation profiling To enable clang compilation profiling: -```cmake +```Shell cmake -DBUILD_CLANG_PROFILER=true .. ``` ## b) Using in your application with cmake In `CMakeLists.txt` set your include path to: -```cmake +```Shell include_directories([conjure_enum directory]/include) # e.g. set(cjedir /home/dd/prog/conjure_enum) From c6e1855b8a098a96798b86759084a72dd7df04b4 Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 29 Aug 2024 08:22:12 +1000 Subject: [PATCH 206/235] updated --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 45b300e..7a1866c 100644 --- a/README.md +++ b/README.md @@ -1432,7 +1432,7 @@ This implementation is header only. Apart from standard C++20 includes there are ### i. Build platform #### \*nix based environments To clone and default build the test app, unit tests and the benchmark: -```Shell +```bash git clone https://github.com/fix8mt/conjure_enum.git cd conjure_enum mkdir build @@ -1450,27 +1450,27 @@ The package is also available on [vckpg](https://vcpkg.io/en/package/conjure-enu ### ii. Default compiler warnings By default all warnings are enabled. To prevent this, pass the following to cmake: -```Shell +```bash cmake -DBUILD_ALL_WARNINGS=false .. ``` ### iii. Default unit tests By default the unit tests are built (which will download Catch2). To prevent this, pass the following to cmake: -```Shell +```bash cmake -DBUILD_UNITTESTS=false .. ``` ### iv. Default executable stripping To disable stripping of the executables: -```Shell +```bash cmake -DBUILD_STRIP_EXE=false .. ``` ### v. Clang compilation profiling To enable clang compilation profiling: -```Shell +```bash cmake -DBUILD_CLANG_PROFILER=true .. ``` ## b) Using in your application with cmake In `CMakeLists.txt` set your include path to: -```Shell +```bash include_directories([conjure_enum directory]/include) # e.g. set(cjedir /home/dd/prog/conjure_enum) @@ -1488,7 +1488,7 @@ using namespace FIX8; ## c) Integrating `conjure_enum` in your project with cmake FetchContent You can use cmake [FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html) to integrate `conjure_enum` with your project. If your project was called `myproj` with the sourcefile `myproj.cpp` then... -```cmake +```CMake project(myproj) add_executable (myproj myproj.cpp) set_target_properties(myproj PROPERTIES CXX_STANDARD 20 CXX_STANDARD_REQUIRED true) From 5b6d00940f7d6f400441d43656a63c23e3d8560c Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 29 Aug 2024 08:23:14 +1000 Subject: [PATCH 207/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7a1866c..808863f 100644 --- a/README.md +++ b/README.md @@ -1470,7 +1470,7 @@ cmake -DBUILD_CLANG_PROFILER=true .. ``` ## b) Using in your application with cmake In `CMakeLists.txt` set your include path to: -```bash +```CMake include_directories([conjure_enum directory]/include) # e.g. set(cjedir /home/dd/prog/conjure_enum) From 38b994ad29cd3bc207c1a8f2d5ef2e9b70abd5f4 Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 29 Aug 2024 08:24:17 +1000 Subject: [PATCH 208/235] updated --- README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 808863f..bc91674 100644 --- a/README.md +++ b/README.md @@ -1433,13 +1433,13 @@ This implementation is header only. Apart from standard C++20 includes there are #### \*nix based environments To clone and default build the test app, unit tests and the benchmark: ```bash -git clone https://github.com/fix8mt/conjure_enum.git -cd conjure_enum -mkdir build -cd build -cmake .. -make -j4 -ctest (or make test) +$ git clone https://github.com/fix8mt/conjure_enum.git +$ cd conjure_enum +$ mkdir build +$ cd build +$ cmake .. +$ make -j4 +$ ctest (or make test) ``` #### Windows environments Create a new console project. Add the repo `https://github.com/fix8mt/conjure_enum.git` and clone the source. @@ -1451,22 +1451,22 @@ The package is also available on [vckpg](https://vcpkg.io/en/package/conjure-enu ### ii. Default compiler warnings By default all warnings are enabled. To prevent this, pass the following to cmake: ```bash -cmake -DBUILD_ALL_WARNINGS=false .. +$ cmake -DBUILD_ALL_WARNINGS=false .. ``` ### iii. Default unit tests By default the unit tests are built (which will download Catch2). To prevent this, pass the following to cmake: ```bash -cmake -DBUILD_UNITTESTS=false .. +$ cmake -DBUILD_UNITTESTS=false .. ``` ### iv. Default executable stripping To disable stripping of the executables: ```bash -cmake -DBUILD_STRIP_EXE=false .. +$ cmake -DBUILD_STRIP_EXE=false .. ``` ### v. Clang compilation profiling To enable clang compilation profiling: ```bash -cmake -DBUILD_CLANG_PROFILER=true .. +$ cmake -DBUILD_CLANG_PROFILER=true .. ``` ## b) Using in your application with cmake In `CMakeLists.txt` set your include path to: From 15de40c907d0bd3f265a3984c7d8c5836ee5e300 Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 29 Aug 2024 10:28:01 +1000 Subject: [PATCH 209/235] updated --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index bc91674..fe6605b 100644 --- a/README.md +++ b/README.md @@ -1066,6 +1066,8 @@ Additional methods | :--- | :--- | | `set` | set all specified bits, templated | | `reset` | reset all specified bits, templated | +| `rotl` | rotate underlying left specified times| +| `rotr` | rotate underlying right specified times| | `any_of` | test for one or more bits, templated, function, types and underlyings | | `all_of` | test for all specified bits, templated, function, types and underlyings | | `none_of` | test for all specified bits set to off, templated, function, types and underlyings | @@ -1092,6 +1094,7 @@ eb.reset(); eb[2] = true; eb[numbers::three] = true; std::cout << eb << '\n'; +std::cout << eb.rotr(1) << '\n'; ``` _output_ ``` @@ -1103,6 +1106,7 @@ true 1000000001 0000000001 0000001100 +0000011000 ``` ## d) Other functions ### i. `operator bool` From cfc2276b2020b1915d3644db73925233c7a9f97f Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 29 Aug 2024 10:38:41 +1000 Subject: [PATCH 210/235] updated --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index fe6605b..b801499 100644 --- a/README.md +++ b/README.md @@ -1072,6 +1072,7 @@ Additional methods | `all_of` | test for all specified bits, templated, function, types and underlyings | | `none_of` | test for all specified bits set to off, templated, function, types and underlyings | | `not_count` | complement of count, count of off bits | +| `has_single_bit` | if bitset is an integral power of two; otherwise false| Take a look at the [implementation](include/fix8/conjure_enum.hpp) for more detail on the various API functions available. You can also review the unit test cases for examples of use. From a697f67e035e5fda6dac3e84b7de784188856280 Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 29 Aug 2024 10:39:36 +1000 Subject: [PATCH 211/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b801499..b4fa990 100644 --- a/README.md +++ b/README.md @@ -1072,7 +1072,7 @@ Additional methods | `all_of` | test for all specified bits, templated, function, types and underlyings | | `none_of` | test for all specified bits set to off, templated, function, types and underlyings | | `not_count` | complement of count, count of off bits | -| `has_single_bit` | if bitset is an integral power of two; otherwise false| +| `has_single_bit` | return true if bitset is an integral power of two| Take a look at the [implementation](include/fix8/conjure_enum.hpp) for more detail on the various API functions available. You can also review the unit test cases for examples of use. From 878c6f778ca4933aefa222548b0bd95bca9fb3f6 Mon Sep 17 00:00:00 2001 From: David Dight Date: Fri, 30 Aug 2024 06:02:49 +1000 Subject: [PATCH 212/235] updated --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index b4fa990..f5fd438 100644 --- a/README.md +++ b/README.md @@ -1068,6 +1068,10 @@ Additional methods | `reset` | reset all specified bits, templated | | `rotl` | rotate underlying left specified times| | `rotr` | rotate underlying right specified times| +| `countl_zero` | counts number of consecutive underlying `0` bits, starting from the most significant bit | +| `countl_one` | counts number of consecutive underlying `1` bits, starting from the most significant bit | +| `countr_zero` | counts number of consecutive underlying `0` bits, starting from the least significant bit | +| `countr_one` | counts number of consecutive underlying `1` bits, starting from the least significant bit | | `any_of` | test for one or more bits, templated, function, types and underlyings | | `all_of` | test for all specified bits, templated, function, types and underlyings | | `none_of` | test for all specified bits set to off, templated, function, types and underlyings | From 3f1323ce66dfde6867242d369edda62e2a4c2216 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sat, 31 Aug 2024 06:27:36 +1000 Subject: [PATCH 213/235] updated --- README.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index f5fd438..f6d3a99 100644 --- a/README.md +++ b/README.md @@ -1066,18 +1066,21 @@ Additional methods | :--- | :--- | | `set` | set all specified bits, templated | | `reset` | reset all specified bits, templated | -| `rotl` | rotate underlying left specified times| -| `rotr` | rotate underlying right specified times| -| `countl_zero` | counts number of consecutive underlying `0` bits, starting from the most significant bit | -| `countl_one` | counts number of consecutive underlying `1` bits, starting from the most significant bit | -| `countr_zero` | counts number of consecutive underlying `0` bits, starting from the least significant bit | -| `countr_one` | counts number of consecutive underlying `1` bits, starting from the least significant bit | +| `rotl` | rotate left specified times| +| `rotr` | rotate right specified times| +| `countl_zero` | counts number of consecutive `0` bits, starting from the most significant bit | +| `countl_one` | counts number of consecutive `1` bits, starting from the most significant bit | +| `countr_zero` | counts number of consecutive `0` bits, starting from the least significant bit | +| `countr_one` | counts number of consecutive `1` bits, starting from the least significant bit | | `any_of` | test for one or more bits, templated, function, types and underlyings | | `all_of` | test for all specified bits, templated, function, types and underlyings | | `none_of` | test for all specified bits set to off, templated, function, types and underlyings | | `not_count` | complement of count, count of off bits | | `has_single_bit` | return true if bitset is an integral power of two| +> [!NOTE] +> rot[lr] and count[lr] operate on the _used_ bits of the underlying type. + Take a look at the [implementation](include/fix8/conjure_enum.hpp) for more detail on the various API functions available. You can also review the unit test cases for examples of use. From 487f6f3b88d71bdfd268485d53f6f5759bd644ea Mon Sep 17 00:00:00 2001 From: David Dight Date: Sat, 31 Aug 2024 06:28:54 +1000 Subject: [PATCH 214/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f6d3a99..ba6809d 100644 --- a/README.md +++ b/README.md @@ -1079,7 +1079,7 @@ Additional methods | `has_single_bit` | return true if bitset is an integral power of two| > [!NOTE] -> rot[lr] and count[lr] operate on the _used_ bits of the underlying type. +> `rotl`, `rotl`, `countl*` and `countr*` operate on the _used_ bits of the underlying type. Take a look at the [implementation](include/fix8/conjure_enum.hpp) for more detail on the various API functions available. You can also review the unit test cases for examples of use. From 6c61688bd9655f30311b064a1f82214ed1404d5d Mon Sep 17 00:00:00 2001 From: David Dight Date: Sat, 31 Aug 2024 09:04:47 +1000 Subject: [PATCH 215/235] updated --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index ba6809d..fa5bb2b 100644 --- a/README.md +++ b/README.md @@ -1288,6 +1288,13 @@ constexpr U get_unused_bit_mask() const; Returns a bit mask that would mask off the _unused_ bits of the underlying integral.
Returns a bit mask that would mask off the _used_ bits of the underlying integral. +### ix. `std::hash` +```c++ +template +struct std::hash>; +``` +Provides a specialization of `std::hash` for `enum_bitset`. + --- # 5. `conjure_type` `conjure_type` is a general purpose class allowing you to extract a string representation of any typename. From bb61d762362a83617a5dfff728102cf5ebb067ac Mon Sep 17 00:00:00 2001 From: David Dight Date: Sat, 31 Aug 2024 09:05:51 +1000 Subject: [PATCH 216/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fa5bb2b..58a2918 100644 --- a/README.md +++ b/README.md @@ -1288,7 +1288,7 @@ constexpr U get_unused_bit_mask() const; Returns a bit mask that would mask off the _unused_ bits of the underlying integral.
Returns a bit mask that would mask off the _used_ bits of the underlying integral. -### ix. `std::hash` +### ix. `std::hash>` ```c++ template struct std::hash>; From 65578974b0dc9d703b982e4852c638c4dc3009b3 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sat, 31 Aug 2024 17:01:05 +1000 Subject: [PATCH 217/235] pre-rel 1.1f --- examples/example.cpp | 2 ++ include/fix8/conjure_enum_bitset.hpp | 27 +++++++++++++++++++++++++-- utests/unittests.cpp | 24 ++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/examples/example.cpp b/examples/example.cpp index d9fa14f..5498b96 100644 --- a/examples/example.cpp +++ b/examples/example.cpp @@ -228,5 +228,7 @@ int main(void) std::cout << '"' << component::host << '"' << '\n'; std::cout << '"' << component1::host << '"' << '\n'; std::cout << '"' << static_cast(100) << '"' << '\n'; + + std::cout << std::hash>{}(er) << '\n'; return 0; } diff --git a/include/fix8/conjure_enum_bitset.hpp b/include/fix8/conjure_enum_bitset.hpp index b632915..fc1f9dc 100644 --- a/include/fix8/conjure_enum_bitset.hpp +++ b/include/fix8/conjure_enum_bitset.hpp @@ -71,6 +71,9 @@ class enum_bitset std::conditional_t>>>; static_assert(std::integral, "requested bitset overflow"); + static constexpr U all_bits { (1 << countof) - 1 }; + static constexpr U unused_bits { sizeof(U) * 8 - countof }; + template class _reference { @@ -99,13 +102,14 @@ class enum_bitset template static constexpr U to_underlying() noexcept { return static_cast(val); } // C++23: upgrade to std::to_underlying static constexpr U to_underlying(T val) noexcept { return static_cast(val); } - static constexpr U all_bits { (1 << countof) - 1 }; U _present{}; #if __has_include() static constexpr std::array _hexfmtarr { "{:#x}", "{:#X}", "{:x}", "{:#X}" }; #endif + static constexpr int correct_count(int val) noexcept { return val ? val - unused_bits : 0; } + public: using enum_bitset_underlying_type = U; using reference = _reference; @@ -130,6 +134,10 @@ class enum_bitset constexpr std::size_t count() const noexcept { return std::popcount(static_cast>(_present)); } // C++23: upgrade to std::bitset when count is constexpr constexpr std::size_t not_count() const noexcept { return countof - count(); } + constexpr int countl_zero() const noexcept { return correct_count(std::countl_zero(_present)); } + constexpr int countl_one() const noexcept { return correct_count(std::countl_one(_present)); } + constexpr int countr_zero() const noexcept { return std::countr_zero(_present); } + constexpr int countr_one() const noexcept { return std::countr_one(_present); } constexpr std::size_t size() const noexcept { return countof; } constexpr unsigned long to_ulong() const { @@ -181,6 +189,10 @@ class enum_bitset constexpr void flip(U pos) noexcept { _present ^= 1 << pos; } constexpr void flip(T what) noexcept { flip(to_underlying(what)); } + /// rotate + constexpr enum_bitset& rotl(int cnt) noexcept { set(_present << cnt | _present >> (countof * 8 - cnt)); return *this; } + constexpr enum_bitset& rotr(int cnt) noexcept { set(_present >> cnt | _present << (countof * 8 - cnt)); return *this; } + /// reset template constexpr void reset() noexcept @@ -244,9 +256,9 @@ class enum_bitset constexpr bool any() const noexcept { return count(); } constexpr bool all() const noexcept { return _present == all_bits; } constexpr bool none() const noexcept { return !*this; } + constexpr bool has_single_bit() const noexcept { return std::has_single_bit(_present); } /// operators - constexpr operator bool() const noexcept { return count(); } constexpr enum_bitset& operator<<=(std::size_t pos) noexcept { _present <<= pos; return *this; } constexpr enum_bitset& operator>>=(std::size_t pos) noexcept { _present >>= pos; return *this; } constexpr enum_bitset& operator&=(T other) noexcept { _present &= 1 << to_underlying(other); return *this; } @@ -264,6 +276,7 @@ class enum_bitset constexpr enum_bitset operator~() const noexcept { return enum_bitset(~_present & all_bits); } constexpr operator auto() const noexcept { return std::bitset(_present); } + constexpr operator bool() const noexcept { return count(); } /// for_each, for_each_n template @@ -377,5 +390,15 @@ constexpr enum_bitset operator^(const enum_bitset& lh, const enum_bitset +struct std::hash> +{ + size_t operator()(const FIX8::enum_bitset& bs) const noexcept + { + return std::hash::enum_bitset_underlying_type>()(bs.get_underlying()); + } +}; + #endif // FIX8_CONJURE_ENUM_BITSET_HPP_ diff --git a/utests/unittests.cpp b/utests/unittests.cpp index 186d4d6..1414065 100644 --- a/utests/unittests.cpp +++ b/utests/unittests.cpp @@ -666,6 +666,13 @@ TEST_CASE("enum_bitset") REQUIRE(ec.get_underlying_bit_size() == 16); REQUIRE(ec.get_unused_bit_mask() == 0b111111 << 10); REQUIRE(ec.get_bit_mask() == 0b1111111111); + + ec.reset(); + ec.set(); + REQUIRE(ec.countl_one() == 0); + REQUIRE(ec.countr_zero() == 1); + REQUIRE(ec.countr_one() == 0); + REQUIRE(ec.countl_zero() == 6); } //----------------------------------------------------------------------------------------- @@ -711,6 +718,23 @@ TEST_CASE("enum_bitset ops") ed[numbers::two] = true; REQUIRE(ed.test(numbers::two)); REQUIRE(ed[2] == true); + + ed.reset(); + ed.set(); + REQUIRE(ed.rotl(1) == enum_bitset(numbers::two,numbers::four,numbers::seven)); + REQUIRE(ed.rotr(1) == enum_bitset(numbers::one,numbers::three,numbers::six)); + REQUIRE(ed.rotr(1) == enum_bitset(numbers::nine,numbers::two,numbers::five)); + REQUIRE(ed.rotl(4) == enum_bitset(numbers::eight,numbers::one,numbers::four)); + + ed.reset(); + ed.set(); + REQUIRE(ed.has_single_bit()); + ed.set(); + REQUIRE(!ed.has_single_bit()); + + REQUIRE(std::hash>{}(ed) == 14); + + REQUIRE(ed == enum_bitset(numbers::one,numbers::two,numbers::three)); } //----------------------------------------------------------------------------------------- From 2c1eb23e5c1714b9d8bf5c9cffe2c91b0cacb006 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sat, 31 Aug 2024 17:14:29 +1000 Subject: [PATCH 218/235] pre-rel 1.1f --- include/fix8/conjure_enum.hpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 5903513..577685c 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -141,10 +141,7 @@ class cs final : public static_only enum class sval { start, end, anon_str, anon_start }; template // can't have constexpr decompositions! (but why not?) - static constexpr auto get_spec() noexcept - { - return std::get(N)>(_specifics[static_cast(V)]); - } + static constexpr auto get_spec() noexcept { return std::get(N)>(_specifics[static_cast(V)]); } static constexpr auto size() noexcept { return sizeof(_specifics); } }; using stype = cs::stype; From cb2273944525639f9892efc431964c4a09f7a4ec Mon Sep 17 00:00:00 2001 From: David Dight Date: Sun, 1 Sep 2024 11:45:12 +1000 Subject: [PATCH 219/235] updated --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 58a2918..efb1d89 100644 --- a/README.md +++ b/README.md @@ -589,17 +589,19 @@ template // specialisa requires (std::invocable && I > 0) static constexpr void dispatch(T ev, const std::array, I>& disp, C *obj, Args&&... args); ``` -With a given enum, search and call user supplied invocable. Use this method where complex event handling is required, allowing you to easily declare predefined invocable actions +With a given enum, search and call user supplied invocable. A typical use case would be where you want to demux a complex event, allowing you to easily declare predefined invocable actions for different enum values. -Where invocable returns a value, return this value or a user supplied "not found" value. -Where invocable is void, call user supplied "not found" invocable. +- Where invocable returns a value, return this value or a user supplied "not found" value. +- Where invocable is void, call user supplied "not found" invocable. + The first parameter of your invocable must accept an enum value (passed by `dispatch`). Optionally provide any additional parameters. Works with lambdas, member functions, functions etc. There are two versions of `dispatch` - the first takes an enum value, a 'not found' value, and a `std::array` of `std::tuple` of enum and invocable. The second version takes an enum value, and a `std::array` of `std::tuple` of enum and invocable. The last element of the array is called if the enum is not found. This version is intended for use with `void` return invocables. + The second version of each of the above is intended to be used when using a member function - the _first_ parameter passed after your array must be the `this` pointer of the object. You can also use `std::bind` to bind the this pointer and any parameter placeholders when declaring your array. If you wish to pass a `reference` parameter, you must wrap it in `std::ref`. From 53dba04cc7ccb3a9f2599973fcba5e7685d40410 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sun, 1 Sep 2024 11:47:21 +1000 Subject: [PATCH 220/235] updated --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index efb1d89..13cd09d 100644 --- a/README.md +++ b/README.md @@ -596,7 +596,9 @@ for different enum values. - Where invocable is void, call user supplied "not found" invocable. The first parameter of your invocable must accept an enum value (passed by `dispatch`). -Optionally provide any additional parameters. Works with lambdas, member functions, functions etc. +Optionally provide any additional parameters. + +Works with lambdas, member functions, functions etc, compatible with `std::invoke`. There are two versions of `dispatch` - the first takes an enum value, a 'not found' value, and a `std::array` of `std::tuple` of enum and invocable. The second version takes an enum value, and a `std::array` of `std::tuple` of enum and invocable. The last element of the array is called if the enum is not found. From 719224134c6a11235c2a446edfbe95d29df9e45f Mon Sep 17 00:00:00 2001 From: David Dight Date: Sun, 1 Sep 2024 11:54:10 +1000 Subject: [PATCH 221/235] updated --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 13cd09d..0af39d3 100644 --- a/README.md +++ b/README.md @@ -876,6 +876,7 @@ static constexpr int get_actual_enum_max_value(); ``` The first two functions return the min and max enum range for the specified enum. If you have specialised `enum_range` then these values will be reported (see below). + The second two functions return the actual min and max enum values as ints for the specified enum. ```c++ std::cout << conjure_enum::get_enum_min_value() << '/' << conjure_enum::get_enum_min_value() << '\n'; @@ -1450,6 +1451,9 @@ Provides an `ostream` insertor. # 7. Building This implementation is header only. Apart from standard C++20 includes there are no external dependencies needed in your application. [Catch2](https://github.com/catchorg/Catch2.git) is used for the built-in unit tests. +> [!NOTE] +> The unit test source files [unittests.cpp](utests/unittests.cpp) and [edgetests.cpp](utests/edgetests.cpp) contain additional examples for all +> the APIs. ## a) Obtaining the source, building the unittests and examples ### i. Build platform @@ -1651,6 +1655,7 @@ For convenience, two macros are provided to make it easier to set custom ranges #define FIX8_CONJURE_ENUM_SET_RANGE(min_enum,max_enum)... ``` The first macro takes an enum typename followed by a lower and upper int range value. + The second macro takes a lower and upper enum value. For example: ```c++ FIX8_CONJURE_ENUM_SET_RANGE_INTS(numbers, 0, 7) From 96ac45ce2adada95f7fe256b395282b53efa6ab7 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sun, 1 Sep 2024 12:08:53 +1000 Subject: [PATCH 222/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0af39d3..a0474fb 100644 --- a/README.md +++ b/README.md @@ -1451,7 +1451,7 @@ Provides an `ostream` insertor. # 7. Building This implementation is header only. Apart from standard C++20 includes there are no external dependencies needed in your application. [Catch2](https://github.com/catchorg/Catch2.git) is used for the built-in unit tests. -> [!NOTE] +> [!TIP] > The unit test source files [unittests.cpp](utests/unittests.cpp) and [edgetests.cpp](utests/edgetests.cpp) contain additional examples for all > the APIs. From 342505d41296911a97a7491d16c0659d59adc31b Mon Sep 17 00:00:00 2001 From: David Dight Date: Mon, 2 Sep 2024 07:16:46 +1000 Subject: [PATCH 223/235] updated --- README.md | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a0474fb..7b241d1 100644 --- a/README.md +++ b/README.md @@ -147,7 +147,7 @@ numbers::two Because all methods in `conjure_enum` are defined _within_ a `class` instead of individual template functions in a `namespace`, you can reduce your typing with standard aliases: ```c++ -using ec = conjure_enum; +using ec = FIX8::conjure_enum; std::cout << std::format("\"{}\"\n", ec::enum_to_string(component::authority)); std::cout << std::format("\"{}\"\n", ec::enum_to_string(static_cast(100))); ``` @@ -483,13 +483,20 @@ requires std::invocable [[maybe_unused]] static constexpr auto for_each_n(int n, Fn&& func, C *obj, Args&&... args); ``` Call supplied invocable for _each_ enum value. Similar to `std::for_each` except the first parameter of your invocable must accept an enum value (passed by `for_each`). -Optionally provide any additional parameters. Works with lambdas, member functions, functions etc. You can limit the number of calls to your -invocable by using the `for_each_n` version with the first parameter being the maximum number to call. The second version of `for_each` and `for_each_n` is intended to be used +Optionally provide any additional parameters. You can limit the number of calls to your invocable by using the `for_each_n` version with the first parameter +being the maximum number to call. The second version of `for_each` and `for_each_n` is intended to be used when using a member function - the _second_ parameter passed by your call must be the `this` pointer of the object. If you wish to pass a `reference` parameter, you must wrap it in `std::ref`. -Returns `std::bind(std::forward(func), std::placeholders::_1, std::forward(args)...)` -or `std::bind(std::forward(func), obj, std::placeholders::_1, std::forward(args)...)` which can be stored or immediately invoked. +Works with lambdas, member functions, functions etc, compatible with `std::invoke`. + +Returns +```c++ +std::bind(std::forward(func), std::placeholders::_1, std::forward(args)...) +// or +std::bind(std::forward(func), obj, std::placeholders::_1, std::forward(args)...) +``` +which can be stored or immediately invoked. See `enum_bitset::for_each` to iterate through a bitset. ```c++ From 56bffd0bfe728042fe34856da171c2b466fdc15c Mon Sep 17 00:00:00 2001 From: David Dight Date: Mon, 2 Sep 2024 07:17:25 +1000 Subject: [PATCH 224/235] updated --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7b241d1..8718a1d 100644 --- a/README.md +++ b/README.md @@ -492,9 +492,9 @@ Works with lambdas, member functions, functions etc, compatible with `std::invok Returns ```c++ -std::bind(std::forward(func), std::placeholders::_1, std::forward(args)...) +std::bind(std::forward(func), std::placeholders::_1, std::forward(args)...); // or -std::bind(std::forward(func), obj, std::placeholders::_1, std::forward(args)...) +std::bind(std::forward(func), obj, std::placeholders::_1, std::forward(args)...); ``` which can be stored or immediately invoked. From 8cebdbc1cc170f914064a1e2782823144b6896b4 Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 5 Sep 2024 07:30:21 +1000 Subject: [PATCH 225/235] updated --- README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/README.md b/README.md index 8718a1d..5dbe318 100644 --- a/README.md +++ b/README.md @@ -645,6 +645,23 @@ directions::right not found: directions::forward -1 ``` +This example uses lambdas: +```c++ +const auto dd1 +{ + std::to_array>> + ({ + { component::scheme, [](component ev, int a) { return a * 100 + conjure_enum::enum_to_int(ev); } }, + { component::port, [](component ev, int a) { return a * 200 + conjure_enum::enum_to_int(ev); } }, + { component::fragment, [](component ev, int a) { return a * 300 + conjure_enum::enum_to_int(ev); } }, + }) +}; +std::cout << conjure_enum::dispatch(component::port, -1, dd1, 10) << '\n'; +``` +_output_ +```CSV +2006 +``` This example uses member functions: ```c++ struct foo From 4fe7c02dba04810ec96391580cbcf1c8204e16e0 Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 5 Sep 2024 07:31:21 +1000 Subject: [PATCH 226/235] updated --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5dbe318..541a09e 100644 --- a/README.md +++ b/README.md @@ -615,7 +615,9 @@ The second version of each of the above is intended to be used when using a memb You can also use `std::bind` to bind the this pointer and any parameter placeholders when declaring your array. If you wish to pass a `reference` parameter, you must wrap it in `std::ref`. -If you wish to provide a `constexpr` array, you will need to use a simple function prototype, since `std::function` is not constexpr (see unit tests for examples). +> [!TIP] +> If you wish to provide a `constexpr` array, you will need to use a simple function prototype, since `std::function` is not constexpr (see unit tests for examples). + > [!IMPORTANT] > Your `std::array` of `std::tuple` should be sorted by enum. > The `dispatch` method performs a binary search on the array. Complexity for a sorted array is at most  $2log_2(N)+O(1)$  comparisons. From b9c6a2d070edcc19d083b7b5fc2438ffc09b9274 Mon Sep 17 00:00:00 2001 From: David Dight Date: Fri, 6 Sep 2024 15:16:14 +1000 Subject: [PATCH 227/235] pre-rel 1.1g --- include/fix8/conjure_enum_ext.hpp | 30 ++++++++++++++---------------- utests/unittests.cpp | 2 -- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/include/fix8/conjure_enum_ext.hpp b/include/fix8/conjure_enum_ext.hpp index 43da329..154052a 100644 --- a/include/fix8/conjure_enum_ext.hpp +++ b/include/fix8/conjure_enum_ext.hpp @@ -38,18 +38,15 @@ //---------------------------------------------------------------------------------------- private: - template - static constexpr auto _names(std::index_sequence) noexcept + static constexpr bool _scoped_comp(const scoped_tuple& pl, const scoped_tuple& pr) noexcept { - return std::array{{{ _enum_name_v}...}}; + return std::get<0>(pl) < std::get<0>(pr); } template - static constexpr auto _unscoped_entries(std::index_sequence) noexcept + static constexpr auto _names(std::index_sequence) noexcept { - std::array tmp{{{ values[I], _remove_scope(_enum_name_v)}...}}; - std::sort(tmp.begin(), tmp.end(), _tuple_comp_rev); - return tmp; + return std::array{{{ _enum_name_v}...}}; } static constexpr std::string_view _remove_scope(std::string_view what) noexcept @@ -59,6 +56,14 @@ return what; } + template + static constexpr auto _unscoped_entries(std::index_sequence) noexcept + { + std::array tmp{{{ values[I], _remove_scope(_enum_name_v)}...}}; + std::sort(tmp.begin(), tmp.end(), _tuple_comp_rev); + return tmp; + } + template static constexpr auto _scoped_entries(std::index_sequence) noexcept { @@ -90,11 +95,6 @@ return what; } - static constexpr bool _scoped_comp(const scoped_tuple& pl, const scoped_tuple& pr) noexcept - { - return std::get<0>(pl) < std::get<0>(pr); - } - public: static constexpr std::string_view remove_scope(std::string_view what) noexcept { @@ -209,8 +209,7 @@ static constexpr void dispatch(T ev, const std::array, I>& disp, Args&&... args) noexcept { const auto [begin,end] { std::equal_range(disp.cbegin(), std::prev(disp.cend()), std::make_tuple(ev, Fn()), tuple_comp) }; - return begin != end ? std::invoke(std::get(*begin), ev, std::forward(args)...) - : std::invoke(std::get(*std::prev(disp.cend())), ev, std::forward(args)...); + return std::invoke(std::get(begin != end ? *begin : *std::prev(disp.cend())), ev, std::forward(args)...); } template // specialisation for void member function with not found call to last element @@ -218,8 +217,7 @@ static constexpr void dispatch(T ev, const std::array, I>& disp, C *obj, Args&&... args) noexcept { const auto [begin,end] { std::equal_range(disp.cbegin(), std::prev(disp.cend()), std::make_tuple(ev, Fn()), tuple_comp) }; - return begin != end ? std::invoke(std::get(*begin), obj, ev, std::forward(args)...) - : std::invoke(std::get(*std::prev(disp.cend())), obj, ev, std::forward(args)...); + return std::invoke(std::get(begin != end ? *begin : *std::prev(disp.cend())), obj, ev, std::forward(args)...); } // public constexpr data structures diff --git a/utests/unittests.cpp b/utests/unittests.cpp index 1414065..a3fb1f5 100644 --- a/utests/unittests.cpp +++ b/utests/unittests.cpp @@ -733,8 +733,6 @@ TEST_CASE("enum_bitset ops") REQUIRE(!ed.has_single_bit()); REQUIRE(std::hash>{}(ed) == 14); - - REQUIRE(ed == enum_bitset(numbers::one,numbers::two,numbers::three)); } //----------------------------------------------------------------------------------------- From 228f894fb62bc49f96b3c14b4ba97b01bfb55f23 Mon Sep 17 00:00:00 2001 From: David Dight Date: Fri, 6 Sep 2024 17:14:13 +1000 Subject: [PATCH 228/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 541a09e..cedbe3a 100644 --- a/README.md +++ b/README.md @@ -1112,7 +1112,7 @@ Additional methods > [!NOTE] > `rotl`, `rotl`, `countl*` and `countr*` operate on the _used_ bits of the underlying type. -Take a look at the [implementation](include/fix8/conjure_enum.hpp) for more detail on the various API functions available. +Take a look at the [implementation](include/fix8/enum_bitset.hpp) for more detail on the various API functions available. You can also review the unit test cases for examples of use. All accessors and mutators work with enum values or integers as with operators. They also work with multiple values, either as template parameters or From 94c22e6202554fad90aaf391af0ffe3002dc2e7b Mon Sep 17 00:00:00 2001 From: David Dight Date: Fri, 6 Sep 2024 17:14:55 +1000 Subject: [PATCH 229/235] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cedbe3a..a1bfe1a 100644 --- a/README.md +++ b/README.md @@ -1112,7 +1112,7 @@ Additional methods > [!NOTE] > `rotl`, `rotl`, `countl*` and `countr*` operate on the _used_ bits of the underlying type. -Take a look at the [implementation](include/fix8/enum_bitset.hpp) for more detail on the various API functions available. +Take a look at the [implementation](include/fix8/conjure_enum_bitset.hpp) for more detail on the various API functions available. You can also review the unit test cases for examples of use. All accessors and mutators work with enum values or integers as with operators. They also work with multiple values, either as template parameters or From a5f13979398bf90b195fbea115ff5aec7fdaad30 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sat, 7 Sep 2024 05:58:19 +1000 Subject: [PATCH 230/235] updated --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index a1bfe1a..c397a43 100644 --- a/README.md +++ b/README.md @@ -622,6 +622,8 @@ If you wish to pass a `reference` parameter, you must wrap it in `std::ref`. > Your `std::array` of `std::tuple` should be sorted by enum. > The `dispatch` method performs a binary search on the array. Complexity for a sorted array is at most  $2log_2(N)+O(1)$  comparisons. > If the array is _not_ sorted, complexity is linear. +The following example uses a `static constexpr` array of pointers to functions. For bevity the most point to the same function except the last which is +a lambda. ```c++ enum class directions { left, right, up, down, forward, backward, notfound=-1 }; static constexpr auto prn([](directions ev) { std::cout << conjure_enum::enum_to_string(ev) << '\n'; }); From 85c647fa22e3a71d8650fcaf96a06976770216d1 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sat, 7 Sep 2024 05:59:30 +1000 Subject: [PATCH 231/235] updated --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index c397a43..f54afc8 100644 --- a/README.md +++ b/README.md @@ -622,6 +622,7 @@ If you wish to pass a `reference` parameter, you must wrap it in `std::ref`. > Your `std::array` of `std::tuple` should be sorted by enum. > The `dispatch` method performs a binary search on the array. Complexity for a sorted array is at most  $2log_2(N)+O(1)$  comparisons. > If the array is _not_ sorted, complexity is linear. + The following example uses a `static constexpr` array of pointers to functions. For bevity the most point to the same function except the last which is a lambda. ```c++ From 1e97790a7ade793c2664b5bf95b237f488545ce7 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sat, 7 Sep 2024 06:01:13 +1000 Subject: [PATCH 232/235] updated --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f54afc8..1cd670f 100644 --- a/README.md +++ b/README.md @@ -623,7 +623,7 @@ If you wish to pass a `reference` parameter, you must wrap it in `std::ref`. > The `dispatch` method performs a binary search on the array. Complexity for a sorted array is at most  $2log_2(N)+O(1)$  comparisons. > If the array is _not_ sorted, complexity is linear. -The following example uses a `static constexpr` array of pointers to functions. For bevity the most point to the same function except the last which is +The following example uses a `static constexpr` array of pointers to functions. For brevity they all point to the same function except the last which is a lambda. ```c++ enum class directions { left, right, up, down, forward, backward, notfound=-1 }; @@ -641,12 +641,14 @@ static constexpr auto tarr }) }; conjure_enum::dispatch(directions::right, tarr); +conjure_enum::dispatch(directions::down, tarr); conjure_enum::dispatch(directions::forward, tarr); std::cout << conjure_enum::enum_to_int(directions::notfound) << '\n'; ``` _output_ ```CSV directions::right +directions::down not found: directions::forward -1 ``` From 3bf412aac31ff0b2cf92d53631cdee82e577e46a Mon Sep 17 00:00:00 2001 From: David Dight Date: Sat, 7 Sep 2024 09:29:51 +1000 Subject: [PATCH 233/235] updated --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1cd670f..86b6c29 100644 --- a/README.md +++ b/README.md @@ -847,9 +847,8 @@ static constexpr auto back(); These methods return `*cbegin()` and `*std::prev(cend())` respectively all from `entries` defined above. ```c++ -using en = conjure_enum; -std::cout << static_cast(std::get<0>(en::front())) << ' ' << std::get<1>(en::front()) << '\n'; -std::cout << static_cast(std::get<0>(en::back())) << ' ' << std::get<1>(en::back()) << '\n'; +for (const auto& [ev,str] : {conjure_enum::front(), conjure_enum::back()}) + std::cout << static_cast(ev) << ' ' << str << '\n'; ``` _output_ ```CSV From dfd95b497170b23c50c7b425a628b3261005bf0f Mon Sep 17 00:00:00 2001 From: David Dight Date: Sun, 8 Sep 2024 10:21:24 +1000 Subject: [PATCH 234/235] pre-rel 1.1g --- examples/example.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/examples/example.cpp b/examples/example.cpp index 5498b96..ec8188d 100644 --- a/examples/example.cpp +++ b/examples/example.cpp @@ -54,6 +54,24 @@ enum component1 : int { scheme, authority, userinfo, user, password, host, port, enum class numbers : int { zero, one, two, three, four, five, six, seven, eight, nine }; enum class numbers1 : int { zero1=4, one1=3, two1=2, three1, four1, five1, six1, seven1, eight1, nine1 }; +//----------------------------------------------------------------------------------------- +struct foo1 +{ + int process(component val, int aint) const + { + return aint * static_cast(val); + } + static constexpr auto dd2a + { + std::to_array> + ({ + { component::scheme, &foo1::process }, + { component::port, &foo1::process }, + { component::fragment, &foo1::process }, + }) + }; +}; + //----------------------------------------------------------------------------------------- template const std::string demangle() noexcept @@ -73,6 +91,7 @@ const std::string demangle() noexcept return typeid(T).name(); } +//----------------------------------------------------------------------------------------- int main(void) { conjure_enum::for_each_n(3, [](component val, int other) { std::cout << static_cast(val) << ' ' << other << '\n'; }, 200); @@ -230,5 +249,13 @@ int main(void) std::cout << '"' << static_cast(100) << '"' << '\n'; std::cout << std::hash>{}(er) << '\n'; + + foo1 bar1; + std::cout << conjure_enum::dispatch(component::port, -1, foo1::dd2a, &bar1, 1000) << '\n'; + + using en = conjure_enum; + for (const auto& [ev,str] : {en::front(), en::back()}) + std::cout << static_cast(ev) << ' ' << str << '\n'; + return 0; } From 871b388f375bdb41e60fb1be4c78c3200cb38b42 Mon Sep 17 00:00:00 2001 From: David Dight Date: Mon, 9 Sep 2024 16:54:52 +1000 Subject: [PATCH 235/235] pre-rel 1.1g --- include/fix8/conjure_enum.hpp | 2 +- utests/unittests.cpp | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/include/fix8/conjure_enum.hpp b/include/fix8/conjure_enum.hpp index 577685c..264c24b 100644 --- a/include/fix8/conjure_enum.hpp +++ b/include/fix8/conjure_enum.hpp @@ -195,7 +195,7 @@ class conjure_enum : public static_only { static constexpr int enum_min_value{enum_range::min}, enum_max_value{enum_range::max}; static_assert(enum_max_value > enum_min_value, - "FIX8_CONJURE_ENUM_MAX_VALUE, enum_range::max or T::ce_first must be greater than FIX8_CONJURE_ENUM_MIN_VALUE, enum_range::min or T::ce_last) "); + "FIX8_CONJURE_ENUM_MAX_VALUE, enum_range::max or T::ce_last must be greater than FIX8_CONJURE_ENUM_MIN_VALUE, enum_range::min or T::ce_first) "); public: using enum_tuple = std::tuple; diff --git a/utests/unittests.cpp b/utests/unittests.cpp index a3fb1f5..278794f 100644 --- a/utests/unittests.cpp +++ b/utests/unittests.cpp @@ -68,6 +68,7 @@ enum class numbers64 : uint64_t fifty_five, fifty_six, fifty_seven, fifty_eight, fifty_nine, sixty, sixty_one, sixty_two, sixty_three }; +enum class reverse_range_test { first=7, second=6, third=5, fourth=4, fifth=3, sixth=2, seventh=1, eighth=0 }; //----------------------------------------------------------------------------------------- // run as: ctest --output-on-failure @@ -93,6 +94,10 @@ TEST_CASE("default range") REQUIRE(conjure_enum::get_enum_max_value() == FIX8_CONJURE_ENUM_MAX_VALUE); REQUIRE(conjure_enum::get_actual_enum_min_value() == 0); REQUIRE(conjure_enum::get_actual_enum_max_value() == 14); + REQUIRE(conjure_enum::get_enum_min_value() == FIX8_CONJURE_ENUM_MIN_VALUE); + REQUIRE(conjure_enum::get_enum_max_value() == FIX8_CONJURE_ENUM_MAX_VALUE); + REQUIRE(conjure_enum::get_actual_enum_min_value() == 0); + REQUIRE(conjure_enum::get_actual_enum_max_value() == 7); } //----------------------------------------------------------------------------------------- @@ -148,6 +153,7 @@ TEST_CASE("is_continuous") { REQUIRE(!conjure_enum::is_continuous()); REQUIRE(conjure_enum::is_continuous()); + REQUIRE(conjure_enum::is_continuous()); } //----------------------------------------------------------------------------------------- @@ -321,6 +327,10 @@ TEST_CASE("iterators") REQUIRE(std::get(conjure_enum::front()) == scheme); REQUIRE(std::get(conjure_enum::back()) == fragment); REQUIRE(std::get(conjure_enum::back()) == std::get(*conjure_enum::crbegin())); + REQUIRE(std::get(conjure_enum::front()) == reverse_range_test::eighth); + REQUIRE(std::get(conjure_enum::back()) == reverse_range_test::first); + REQUIRE(std::get(conjure_enum::front()) == conjure_enum::min_v); + REQUIRE(std::get(conjure_enum::back()) == conjure_enum::max_v); } //-----------------------------------------------------------------------------------------