Skip to content

Commit 3455f33

Browse files
authored
Merge pull request #11 from fix8mt/dev
Dev pre1.0j to Master
2 parents 45a9d09 + b44f48a commit 3455f33

File tree

3 files changed

+113
-10
lines changed

3 files changed

+113
-10
lines changed

README.md

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,8 @@ _output_
500500
14 10
501501
14 10 <== invoked with returned object
502502
74
503-
```Example with pointer to member function with additional parameters:
503+
```
504+
Example with pointer to member function with additional parameters:
504505
```c++
505506
struct foo
506507
{
@@ -555,7 +556,7 @@ You can also use `std::bind` to bind the this pointer and any parameter placehol
555556
If you wish to pass a `reference` parameter, you must wrap it in `std::ref`.
556557
557558
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).
558-
> [!TIP]
559+
> [!IMPORTANT]
559560
> Your `std::array` of `std::tuple` should be sorted by enum.
560561
> The `dispatch` method performs a binary search on the array. Complexity for a sorted array is at most $2log_2(N)+O(1)$ comparisons.
561562
> If the array is _not_ sorted, complexity is linear.
@@ -1034,7 +1035,7 @@ template<typename C, typename Fn, typename... Args> // specialisation for member
10341035
requires std::invocable<Fn&&, C, T, Args...>
10351036
[[maybe_unused]] constexpr auto for_each_n(int n, Fn&& func, C *obj, Args&&... args);
10361037
```
1037-
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`).
1038+
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`).
10381039
Optionally provide any additional parameters. Works with lambdas, member functions, functions etc. You can limit the number of calls to your
10391040
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
10401041
when using a member function - the _second_ parameter passed by your call must be the `this` pointer of the object.
@@ -1043,7 +1044,7 @@ If you wish to pass a `reference` parameter, you must wrap it in `std::ref`.
10431044
Returns `std::bind(std::forward<Fn>(func), std::placeholders::_1, std::forward<Args>(args)...)` or
10441045
`std::bind(std::forward<Fn>(func), obj, std::placeholders::_1, std::forward<Args>(args)...)` which can be stored or immediately invoked.
10451046
1046-
To iterate over each bit regardless of whether it is on or not, use `conjure_enum<T>::for_each`.
1047+
To iterate over every bit regardless of whether it is on or not, use `conjure_enum<T>::for_each`.
10471048
10481049
Example using member function:
10491050
```c++
@@ -1076,6 +1077,36 @@ numbers::two
10761077
numbers::five
10771078
```
10781079

1080+
### iv. Using `conjure_enum::dispatch` with `enum_bitset`
1081+
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:
1082+
```c++
1083+
const auto dd3
1084+
{
1085+
std::to_array<std::tuple<numbers, std::function<void(numbers, int)>>>
1086+
({
1087+
{ numbers::one, [](numbers ev, int a)
1088+
{ std::cout << 1000 + a + conjure_enum<numbers>::enum_to_int(ev) << '\n'; } },
1089+
{ numbers::two, [](numbers ev, int a)
1090+
{ std::cout << 2000 + a + conjure_enum<numbers>::enum_to_int(ev) << '\n'; } },
1091+
{ numbers::three, [](numbers ev, int a)
1092+
{ std::cout << 3000 + a + conjure_enum<numbers>::enum_to_int(ev) << '\n'; } },
1093+
{ static_cast<numbers>(-1), [](numbers ev, [[maybe_unused]] int a)
1094+
{ std::cout << "not found: " << conjure_enum<numbers>::enum_to_int(ev) << '\n'; } }, // not found func
1095+
})
1096+
};
1097+
enum_bitset<numbers>(1,2,3,5).for_each([](numbers val, const auto& arr, int num)
1098+
{
1099+
conjure_enum<numbers>::dispatch(val, arr, num);
1100+
}, dd3, 100);
1101+
```
1102+
_output_
1103+
```CSV
1104+
1101
1105+
2102
1106+
3103
1107+
not found: 5
1108+
```
1109+
10791110
---
10801111
# 5. API and Examples using `conjure_type`
10811112
`conjure_type` is a general purpose class allowing you to extract a string representation of any typename.
@@ -1449,7 +1480,7 @@ It can be observed that there is only _one_ copy of the scoped enum value string
14491480
| :--- | :--- | :--- | ---: |
14501481
| [gcc](https://gcc.gnu.org/projects/cxx-status.html) | `11`, `12`, `13`, `14`| `std::format` not complete in `11`, `12` | `<= 10` |
14511482
| [clang](https://clang.llvm.org/cxx_status.html) | `15`, `16`, `17`, `18`| Catch2 needs `cxx_std_20` in `15` | `<= 14` |
1452-
| [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`|
1483+
| [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`|
14531484
| [xcode](https://developer.apple.com/support/xcode/) | `15` | Apple LLVM 15.0.0, some issues with `constexpr`, workarounds| `<= 14`|
14541485

14551486
# 9. Compiler issues

examples/srcloctest.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,16 @@ int main(int argc, char **argv)
158158
result->second ^= true;
159159
if (hlp)
160160
{
161-
std::cout << "Usage: " << argv[0] << " [-cmh]" << R"(
161+
std::cout << R"(
162+
This program shows the output generated by your compiler. There are nine different
163+
sets of tests - conjure_enum and conjure_type use this information to inform the
164+
parsing algorithm to extract enum and type info. For most compilers, there will be
165+
few if any differences between compiler versions - certainly few that impact
166+
conjure_enum - however there have been a couple of changes with earlier releases.
167+
Since the output of std::source_location is entirely implementation dependent, future
168+
changes may occur.
169+
170+
Usage: )" << argv[0] << " [-cmh]" << R"(
162171
-c show compiler (default true)
163172
-m output using markdown
164173
-h help

utests/unittests.cpp

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,15 @@ TEST_CASE("iterators")
232232
REQUIRE(std::get<component1>(conjure_enum<component1>::back()) == std::get<component1>(*conjure_enum<component1>::crbegin()));
233233
}
234234

235+
//-----------------------------------------------------------------------------------------
236+
TEST_CASE("iterator_adaptor")
237+
{
238+
int tot{};
239+
for (const auto& itr : iterator_adaptor<component>())
240+
tot += static_cast<int>(std::get<0>(itr));
241+
REQUIRE(tot == 60);
242+
}
243+
235244
//-----------------------------------------------------------------------------------------
236245
TEST_CASE("string_to_enum")
237246
{
@@ -414,7 +423,7 @@ TEST_CASE("dispatch")
414423
REQUIRE(total1 == -1);
415424

416425
// test empty
417-
const std::array<std::tuple<component, std::function<int(component)>>, 0> dd4;
426+
const std::array<std::tuple<component, std::function<int(component)>>, 0> dd4{};
418427
REQUIRE(conjure_enum<component>::dispatch(component::path, -1, dd4) == -1);
419428

420429
const std::array<std::tuple<component, std::function<void(component, int&)>>, 1> dd5
@@ -457,15 +466,15 @@ TEST_CASE("constexpr dispatch")
457466

458467
struct foo
459468
{
460-
int process(component val, int aint)
469+
int process(component val, int aint) const
461470
{
462471
return aint * static_cast<int>(val);
463472
}
464473
};
465474
foo bar;
466475
constexpr auto dd2a
467476
{
468-
std::to_array<std::tuple<component, int (foo::*)(component, int)>>
477+
std::to_array<std::tuple<component, int (foo::*)(component, int) const>>
469478
({
470479
{ component::scheme, &foo::process },
471480
{ component::port, &foo::process },
@@ -475,7 +484,7 @@ TEST_CASE("constexpr dispatch")
475484
REQUIRE(conjure_enum<component>::dispatch(component::port, -1, dd2a, &bar, 1000) == 6000);
476485

477486
// test empty
478-
constexpr std::array<std::tuple<component, int (*)(component)>, 0> dd4;
487+
constexpr std::array<std::tuple<component, int (*)(component)>, 0> dd4{};
479488
REQUIRE(conjure_enum<component>::dispatch(component::path, -1, dd4) == -1);
480489

481490
constexpr std::array<std::tuple<component, void (*)(component, int&)>, 1> dd5
@@ -645,3 +654,57 @@ numbers::five(5)
645654
REQUIRE(total == 9);
646655
}
647656

657+
//-----------------------------------------------------------------------------------------
658+
TEST_CASE("enum_bitset using conjure_enum::dispatch")
659+
{
660+
struct foo
661+
{
662+
int total{};
663+
int process(numbers val, int aint) const
664+
{
665+
return aint * static_cast<int>(val);
666+
}
667+
int process1(numbers val, int aint) const
668+
{
669+
return aint + static_cast<int>(val);
670+
}
671+
int process2(numbers val, int aint) const
672+
{
673+
return aint - static_cast<int>(val);
674+
}
675+
};
676+
constexpr auto tarr
677+
{
678+
std::to_array<std::tuple<numbers, int (foo::*)(numbers, int) const>>
679+
({
680+
{ numbers::two, &foo::process },
681+
{ numbers::three, &foo::process1 },
682+
{ numbers::four, &foo::process2 },
683+
})
684+
};
685+
foo bar;
686+
enum_bitset<numbers> enc(numbers::two,numbers::three,numbers::four,numbers::five);
687+
enc.for_each([](numbers val, const auto& arr, foo *ptr, int extr)
688+
{
689+
ptr->total += conjure_enum<numbers>::dispatch(val, -1, arr, ptr, extr);
690+
}, tarr, &bar, 1000);
691+
REQUIRE(bar.total == 3998);
692+
693+
const auto dd2
694+
{
695+
std::to_array<std::tuple<numbers, std::function<void(numbers, int&)>>>
696+
({
697+
{ numbers::one, [](numbers ev, int& a) { a += 1000 + conjure_enum<numbers>::enum_to_int(ev); } },
698+
{ numbers::two, [](numbers ev, int& a) { a += 2000 + conjure_enum<numbers>::enum_to_int(ev); } },
699+
{ numbers::three, [](numbers ev, int& a) { a += 3000 + conjure_enum<numbers>::enum_to_int(ev); } },
700+
{ static_cast<numbers>(-1), []([[maybe_unused]] numbers ev, int& a) { a += -1; } }, // not found func
701+
})
702+
};
703+
int total{};
704+
enum_bitset<numbers>(1,2,3,5).for_each([](numbers val, const auto& arr, int& tot)
705+
{
706+
conjure_enum<numbers>::dispatch(val, arr, tot);
707+
}, dd2, std::ref(total));
708+
REQUIRE(total == 6005);
709+
}
710+

0 commit comments

Comments
 (0)