If you need to perform the run-time lookup, the following method would work with the complexity O(1) in both directions.
Since all your enumerators of A
and B
are not initialized, the first enumerator has the value of zero, the second one has the value of 1
, and so on.
Regarding these zero-starting integers as indices of arrays, we can construct a bidirectional map using two arrays.
For instance, assuming the current mapping as
A::FirstA (=0) <--> B::SecondB (=1),
A::SecondA (=1) <--> B::FirstB (=0),
, then let us define the following two arrays
A arrA[2] = {A::SecondA, A::FirstA},
B arrB[2] = {B::SecondB, B::FirstB},
where arrA[i]
is the enumerator of A
corresponding to i
-th enumerator of B
, and vice versa.
In this setup, we can perform a lookup from A a
to B
as arrB[std::size(a)]
, and vice versa, with the complexity O(1).
The following class biENumMap
is an implementation example of the above bidirectional method with C++14 and over.
Please note that since the extended constexpr is available from C++14, here the ctor also can be a constant expression.
Two overloads operator()
are lookup functions from A
and B
, respectively.
These can also be constant expressions and this class enables us to perform bidirectional lookup at both compile-time and run-time:
template<std::size_t N>
class biENumMap
{
A arrA[N];
B arrB[N];
public:
constexpr biENumMap(const std::array<std::pair<A,B>, N>& init)
: arrA(), arrB()
{
for(std::size_t i = 0; i < N; ++i)
{
const auto& p = init[i];
arrA[static_cast<std::size_t>(p.second)] = p.first;
arrB[static_cast<std::size_t>(p.first) ] = p.second;
}
}
constexpr A operator()(B b) const{
return arrA[static_cast<std::size_t>(b)];
}
constexpr B operator()(A a) const{
return arrB[static_cast<std::size_t>(a)];
}
};
We can use this class as follows:
DEMO
// compile-time construction.
constexpr biEnumMap<3> mapper({{
{A::FirstA , B::SecondB },
{A::SecondA , B::FirstB },
{A::InvalidA, B::InvalidB} }});
// compile-time tests, A to B.
static_assert(mapper(A::FirstA ) == B::SecondB );
static_assert(mapper(A::SecondA ) == B::FirstB );
static_assert(mapper(A::InvalidA) == B::InvalidB);
// compile-time tests, B to A.
static_assert(mapper(B::FirstB ) == A::SecondA );
static_assert(mapper(B::SecondB ) == A::FirstA );
static_assert(mapper(B::InvalidB) == A::InvalidA);
// run-time tests, A to B.
std::vector<A> vA = {A::FirstA, A::SecondA, A::InvalidA};
assert(mapper(vA[0]) == B::SecondB );
assert(mapper(vA[1]) == B::FirstB );
assert(mapper(vA[2]) == B::InvalidB);
// run-time tests, B to A.
std::vector<B> vB = {B::FirstB, B::SecondB, B::InvalidB};
assert(mapper(vB[0]) == A::SecondA );
assert(mapper(vB[1]) == A::FirstA );
assert(mapper(vB[2]) == A::InvalidA);