From f05f4aa2883cd105a5e003faa467a20e84d0e5b8 Mon Sep 17 00:00:00 2001 From: David Dight Date: Thu, 11 Jul 2024 19:44:34 +0000 Subject: [PATCH 01/12] updated --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b85ef43..21b2a5c 100644 --- a/README.md +++ b/README.md @@ -500,7 +500,8 @@ _output_ 14 10 14 10 <== invoked with returned object 74 -```Example with pointer to member function with additional parameters: +``` +Example with pointer to member function with additional parameters: ```c++ struct foo { From f196d87b59b5326fef7dc69afc498750d96cc7ee Mon Sep 17 00:00:00 2001 From: David Dight Date: Sun, 14 Jul 2024 21:16:07 +0000 Subject: [PATCH 02/12] updated --- README.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/README.md b/README.md index 21b2a5c..172de6e 100644 --- a/README.md +++ b/README.md @@ -1077,6 +1077,32 @@ numbers::two numbers::five ``` +### Using `conjure_enum::dispatch` with `enum_bitset` +Using an `enum_bitset` can be a convenient way of iterating through a set of bits to call specific functions on each. The following demonstrates this: +```c++ +const auto dd3 +{ + std::to_array>> + ({ + { numbers::one, [](numbers ev, int a) { std::cout << 1000 + a + conjure_enum::enum_to_int(ev) << '\n'; } }, + { numbers::two, [](numbers ev, int a) { std::cout << 2000 + a + conjure_enum::enum_to_int(ev) << '\n'; } }, + { numbers::three, [](numbers ev, int a) { std::cout << 3000 + a + conjure_enum::enum_to_int(ev) << '\n'; } }, + { static_cast(-1), [](numbers ev, [[maybe_unused]] int a) { std::cout << "not found: " << conjure_enum::enum_to_int(ev) << '\n'; } }, // not found func + }) +}; +enum_bitset(1,2,3,5).for_each([](numbers val, const auto& arr, int num) +{ + conjure_enum::dispatch(val, arr, num); +}, dd3, 100); +``` +_output_ +```CSV +1101 +2102 +3103 +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. From b03e34a40bdd0dfc5dc596a6f2d1ee9f0e3f3082 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sun, 14 Jul 2024 21:16:48 +0000 Subject: [PATCH 03/12] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 172de6e..e7fa0e2 100644 --- a/README.md +++ b/README.md @@ -1077,7 +1077,7 @@ numbers::two numbers::five ``` -### Using `conjure_enum::dispatch` with `enum_bitset` +### iv. Using `conjure_enum::dispatch` with `enum_bitset` Using an `enum_bitset` can be a convenient way of iterating through a set of bits to call specific functions on each. The following demonstrates this: ```c++ const auto dd3 From dc60d01d71d7a211378ba26697ae4864dc304ac8 Mon Sep 17 00:00:00 2001 From: David Dight Date: Sun, 14 Jul 2024 21:17:26 +0000 Subject: [PATCH 04/12] updated --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index e7fa0e2..4679572 100644 --- a/README.md +++ b/README.md @@ -1082,17 +1082,17 @@ Using an `enum_bitset` can be a convenient way of iterating through a set of bit ```c++ const auto dd3 { - std::to_array>> - ({ - { numbers::one, [](numbers ev, int a) { std::cout << 1000 + a + conjure_enum::enum_to_int(ev) << '\n'; } }, - { numbers::two, [](numbers ev, int a) { std::cout << 2000 + a + conjure_enum::enum_to_int(ev) << '\n'; } }, - { numbers::three, [](numbers ev, int a) { std::cout << 3000 + a + conjure_enum::enum_to_int(ev) << '\n'; } }, - { static_cast(-1), [](numbers ev, [[maybe_unused]] int a) { std::cout << "not found: " << conjure_enum::enum_to_int(ev) << '\n'; } }, // not found func - }) + std::to_array>> + ({ + { numbers::one, [](numbers ev, int a) { std::cout << 1000 + a + conjure_enum::enum_to_int(ev) << '\n'; } }, + { numbers::two, [](numbers ev, int a) { std::cout << 2000 + a + conjure_enum::enum_to_int(ev) << '\n'; } }, + { numbers::three, [](numbers ev, int a) { std::cout << 3000 + a + conjure_enum::enum_to_int(ev) << '\n'; } }, + { static_cast(-1), [](numbers ev, [[maybe_unused]] int a) { std::cout << "not found: " << conjure_enum::enum_to_int(ev) << '\n'; } }, // not found func + }) }; enum_bitset(1,2,3,5).for_each([](numbers val, const auto& arr, int num) { - conjure_enum::dispatch(val, arr, num); + conjure_enum::dispatch(val, arr, num); }, dd3, 100); ``` _output_ From 90077f51aafc1bf17ee18c9e0075e8c37cdace3e Mon Sep 17 00:00:00 2001 From: David Dight Date: Sun, 14 Jul 2024 21:18:11 +0000 Subject: [PATCH 05/12] updated --- README.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4679572..58bcb8b 100644 --- a/README.md +++ b/README.md @@ -1084,10 +1084,14 @@ const auto dd3 { std::to_array>> ({ - { numbers::one, [](numbers ev, int a) { std::cout << 1000 + a + conjure_enum::enum_to_int(ev) << '\n'; } }, - { numbers::two, [](numbers ev, int a) { std::cout << 2000 + a + conjure_enum::enum_to_int(ev) << '\n'; } }, - { numbers::three, [](numbers ev, int a) { std::cout << 3000 + a + conjure_enum::enum_to_int(ev) << '\n'; } }, - { static_cast(-1), [](numbers ev, [[maybe_unused]] int a) { std::cout << "not found: " << conjure_enum::enum_to_int(ev) << '\n'; } }, // not found func + { numbers::one, [](numbers ev, int a) + { std::cout << 1000 + a + conjure_enum::enum_to_int(ev) << '\n'; } }, + { numbers::two, [](numbers ev, int a) + { std::cout << 2000 + a + conjure_enum::enum_to_int(ev) << '\n'; } }, + { numbers::three, [](numbers ev, int a) + { std::cout << 3000 + a + conjure_enum::enum_to_int(ev) << '\n'; } }, + { static_cast(-1), [](numbers ev, [[maybe_unused]] int a) + { std::cout << "not found: " << conjure_enum::enum_to_int(ev) << '\n'; } }, // not found func }) }; enum_bitset(1,2,3,5).for_each([](numbers val, const auto& arr, int num) From 639bf9e28744a5e2d32608e547844449c7799fce Mon Sep 17 00:00:00 2001 From: David Dight Date: Sun, 14 Jul 2024 21:28:25 +0000 Subject: [PATCH 06/12] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 58bcb8b..3a47252 100644 --- a/README.md +++ b/README.md @@ -1078,7 +1078,7 @@ numbers::five ``` ### iv. Using `conjure_enum::dispatch` with `enum_bitset` -Using an `enum_bitset` can be a convenient way of iterating through a set of bits to call specific functions on each. The following demonstrates this: +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 { From a24703b578befa5e9ae2341c06404814bb79ad46 Mon Sep 17 00:00:00 2001 From: David Dight Date: Mon, 15 Jul 2024 07:51:15 +0000 Subject: [PATCH 07/12] pre-rel 1.0j --- utests/unittests.cpp | 67 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 65 insertions(+), 2 deletions(-) diff --git a/utests/unittests.cpp b/utests/unittests.cpp index 43e1542..57fc23c 100644 --- a/utests/unittests.cpp +++ b/utests/unittests.cpp @@ -232,6 +232,15 @@ TEST_CASE("iterators") REQUIRE(std::get(conjure_enum::back()) == std::get(*conjure_enum::crbegin())); } +//----------------------------------------------------------------------------------------- +TEST_CASE("iterator_adaptor") +{ + int tot{}; + for (const auto& itr : iterator_adaptor()) + tot += static_cast(std::get<0>(itr)); + REQUIRE(tot == 60); +} + //----------------------------------------------------------------------------------------- TEST_CASE("string_to_enum") { @@ -457,7 +466,7 @@ TEST_CASE("constexpr dispatch") struct foo { - int process(component val, int aint) + int process(component val, int aint) const { return aint * static_cast(val); } @@ -465,7 +474,7 @@ TEST_CASE("constexpr dispatch") foo bar; constexpr auto dd2a { - std::to_array> + std::to_array> ({ { component::scheme, &foo::process }, { component::port, &foo::process }, @@ -645,3 +654,57 @@ numbers::five(5) REQUIRE(total == 9); } +//----------------------------------------------------------------------------------------- +TEST_CASE("enum_bitset using conjure_enum::dispatch") +{ + struct foo + { + int total{}; + int process(numbers val, int aint) const + { + return aint * static_cast(val); + } + int process1(numbers val, int aint) const + { + return aint + static_cast(val); + } + int process2(numbers val, int aint) const + { + return aint - static_cast(val); + } + }; + constexpr auto tarr + { + std::to_array> + ({ + { numbers::two, &foo::process }, + { numbers::three, &foo::process1 }, + { numbers::four, &foo::process2 }, + }) + }; + foo bar; + enum_bitset enc(numbers::two,numbers::three,numbers::four,numbers::five); + enc.for_each([](numbers val, const auto& arr, foo *ptr, int extr) + { + ptr->total += conjure_enum::dispatch(val, -1, arr, ptr, extr); + }, tarr, &bar, 1000); + REQUIRE(bar.total == 3998); + + const auto dd2 + { + std::to_array>> + ({ + { numbers::one, [](numbers ev, int& a) { a += 1000 + conjure_enum::enum_to_int(ev); } }, + { numbers::two, [](numbers ev, int& a) { a += 2000 + conjure_enum::enum_to_int(ev); } }, + { numbers::three, [](numbers ev, int& a) { a += 3000 + conjure_enum::enum_to_int(ev); } }, + { static_cast(-1), []([[maybe_unused]] numbers ev, int& a) { a += -1; } }, // not found func + }) + }; + int total{}; + enum_bitset(1,2,3,5).for_each([](numbers val, const auto& arr, int& tot) + { + conjure_enum::dispatch(val, arr, tot); + }, dd2, std::ref(total)); + REQUIRE(total == 6005); +} + From 7f321fdfeed5b4c970002a45c4fa2574f35c1f33 Mon Sep 17 00:00:00 2001 From: David Dight Date: Mon, 15 Jul 2024 21:25:37 +0000 Subject: [PATCH 08/12] pre-rel 1.0j --- README.md | 2 +- utests/unittests.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3a47252..cef25d1 100644 --- a/README.md +++ b/README.md @@ -1480,7 +1480,7 @@ It can be observed that there is only _one_ copy of the scoped enum value string | :--- | :--- | :--- | ---: | | [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.3`| `<= 16.9`| +| [msvc](https://learn.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance) | `16`, `17` | Visual Studio 2019,2022, latest `17.10.4`| `<= 16.9`| | [xcode](https://developer.apple.com/support/xcode/) | `15` | Apple LLVM 15.0.0, some issues with `constexpr`, workarounds| `<= 14`| # 9. Compiler issues diff --git a/utests/unittests.cpp b/utests/unittests.cpp index 57fc23c..9e8b5d6 100644 --- a/utests/unittests.cpp +++ b/utests/unittests.cpp @@ -423,7 +423,7 @@ TEST_CASE("dispatch") REQUIRE(total1 == -1); // test empty - const std::array>, 0> dd4; + const std::array>, 0> dd4{}; REQUIRE(conjure_enum::dispatch(component::path, -1, dd4) == -1); const std::array>, 1> dd5 From bf0eff03acaa3586a84988c07a87c8fc36ccd33e Mon Sep 17 00:00:00 2001 From: David Dight Date: Mon, 15 Jul 2024 21:26:13 +0000 Subject: [PATCH 09/12] pre-rel 1.0j --- utests/unittests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utests/unittests.cpp b/utests/unittests.cpp index 9e8b5d6..e8208cc 100644 --- a/utests/unittests.cpp +++ b/utests/unittests.cpp @@ -484,7 +484,7 @@ TEST_CASE("constexpr dispatch") REQUIRE(conjure_enum::dispatch(component::port, -1, dd2a, &bar, 1000) == 6000); // test empty - constexpr std::array, 0> dd4; + constexpr std::array, 0> dd4{}; REQUIRE(conjure_enum::dispatch(component::path, -1, dd4) == -1); constexpr std::array, 1> dd5 From dfbafc8e4dd38f61b8b8e38b3dbca741b04ffcc8 Mon Sep 17 00:00:00 2001 From: David Dight Date: Mon, 15 Jul 2024 21:38:41 +0000 Subject: [PATCH 10/12] pre-rel 1.0j --- examples/srcloctest.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/examples/srcloctest.cpp b/examples/srcloctest.cpp index f3e5fd7..61da5a0 100644 --- a/examples/srcloctest.cpp +++ b/examples/srcloctest.cpp @@ -158,7 +158,16 @@ int main(int argc, char **argv) result->second ^= true; if (hlp) { - std::cout << "Usage: " << argv[0] << " [-cmh]" << R"( + std::cout << R"( +This program shows the output generated by your compiler. There are nine different +sets of tests - conjure_enum and conjure_type use this information to inform the +parsing algorithm to extract enum and type info. For most compilers, there will be +few if any differences between compiler versions - certainly few that impact +conjure_enum - however there have been a couple of changes with earlier releases. +Since the output of std::source_location is entirely implementation dependent, future +changes may occur. + +Usage: )" << argv[0] << " [-cmh]" << R"( -c show compiler (default true) -m output using markdown -h help From 4fa6521beaa920397d1d3cec458001286a56b64a Mon Sep 17 00:00:00 2001 From: David Dight Date: Tue, 16 Jul 2024 23:33:10 +0000 Subject: [PATCH 11/12] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cef25d1..9f6cf7f 100644 --- a/README.md +++ b/README.md @@ -556,7 +556,7 @@ You can also use `std::bind` to bind the this pointer and any parameter placehol 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] +> [!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. > If the array is _not_ sorted, complexity is linear. From b44f48ae89f5707d7ab13751ac69822ef4bc36aa Mon Sep 17 00:00:00 2001 From: David Dight Date: Tue, 16 Jul 2024 23:41:22 +0000 Subject: [PATCH 12/12] updated --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9f6cf7f..83a40b7 100644 --- a/README.md +++ b/README.md @@ -1035,7 +1035,7 @@ template // specialisation for member requires std::invocable [[maybe_unused]] constexpr auto for_each_n(int n, Fn&& func, C *obj, Args&&... args); ``` -Call supplied invocable for _each bit that is on_. Similar to `std::for_each` except first parameter of your invocable must accept an enum value (passed by `for_each`). +Call supplied invocable for _every bit that is on_. Similar to `std::for_each` except 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 when using a member function - the _second_ parameter passed by your call must be the `this` pointer of the object. @@ -1044,7 +1044,7 @@ 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. -To iterate over each bit regardless of whether it is on or not, use `conjure_enum::for_each`. +To iterate over every bit regardless of whether it is on or not, use `conjure_enum::for_each`. Example using member function: ```c++