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 c99154e1..54dde607 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 54dde607..5da85246 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 5da85246..0b25a676 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 0b25a676..799e83c0 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 eb974679..5ca96ee5 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 82af360e..cc8ece46 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 799e83c0..8fa6cd0d 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 8fa6cd0d..a20ba870 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 a20ba870..9976d758 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 9976d758..c00aec0d 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 c00aec0d..39330062 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 39330062..ac0f2413 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 ac0f2413..5f8a3bcc 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 5f8a3bcc..7cbf904a 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 7cbf904a..983c3076 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 983c3076..097d5291 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 097d5291..59c16962 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 59c16962..a50d7dc8 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 a50d7dc8..e43e8ff5 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 e43e8ff5..069afc6e 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 069afc6e..b11f41e5 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 b11f41e5..e80e397e 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 e80e397e..3ed2fa10 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 9cf0ed2b..d9fa14fa 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 566831ec..efee3dd0 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 e3afa6b6..7956a1f0 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 5ca96ee5..f769f1fe 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