#include "cpp-gen/Term.h"
#include "cpp-gen/Minterm.h"
#include <catch2/catch_test_macros.hpp>
#include <bitset>
#include <limits>
#include <string>
#include <tuple>
namespace detail {
template <std::size_t, typename>
struct std_get_f;
template <std::size_t _i, typename ..._Ts>
struct std_get_f<_i, std::tuple<_Ts...>> {
using Function =
std::tuple_element_t<_i, std::tuple<_Ts...>> const &(std::tuple<_Ts...> const &);
static constexpr
auto value =
static_cast<Function *>(&std::get<_i, _Ts...>);
};
}
template <std::size_t _i, typename _T>
constexpr auto std_get =
detail::std_get_f<_i, _T>::value;
constexpr
bool isOdd(int const &value) {
return value & 1;
}
constexpr
bool isEven(int const &value) {
return !isOdd(value);
}
constexpr
int popCount(int const &value) {
int result = 0;
for (std::size_t i = 0; i < std::numeric_limits<int>::digits; ++i) {
result += (value >> i) & 1;
}
return result;
}
TEST_CASE("popCount") {
CHECK(0 == popCount(0x00));
CHECK(1 == popCount(0x01));
CHECK(1 == popCount(0x02));
CHECK(2 == popCount(0x03));
CHECK(1 == popCount(0x04));
CHECK(2 == popCount(0x05));
CHECK(2 == popCount(0x06));
CHECK(3 == popCount(0x07));
CHECK(1 == popCount(0x08));
CHECK(2 == popCount(0x09));
CHECK(2 == popCount(0x0A));
CHECK(3 == popCount(0x0B));
CHECK(2 == popCount(0x0C));
CHECK(3 == popCount(0x0D));
CHECK(3 == popCount(0x0E));
CHECK(4 == popCount(0x0F));
CHECK(1 == popCount(0x10));
CHECK(2 == popCount(0x11));
CHECK(2 == popCount(0x12));
CHECK(3 == popCount(0x13));
CHECK(2 == popCount(0x14));
CHECK(3 == popCount(0x15));
CHECK(3 == popCount(0x16));
CHECK(4 == popCount(0x17));
CHECK(2 == popCount(0x18));
CHECK(3 == popCount(0x19));
CHECK(3 == popCount(0x1A));
CHECK(4 == popCount(0x1B));
CHECK(3 == popCount(0x1C));
CHECK(4 == popCount(0x1D));
CHECK(4 == popCount(0x1E));
CHECK(5 == popCount(0x1F));
}
struct Foo {
std::string name;
int value;
};
struct Bar {
int value;
};
struct Aggregate {
Foo foo;
Bar bar;
};
constexpr
auto aggFooValue =
Term<&Aggregate::foo, &Foo::value>{};
constexpr
auto aggBarValue =
Term<&Aggregate::bar, &Bar::value>{};
constexpr
auto fooEqBar =
aggFooValue == aggBarValue;
using FooFoo = std::pair<Foo, Foo>;
constexpr
auto fooEqFoo =
Term<&FooFoo::first, &Foo::value>{} == Term<&FooFoo::second, &Foo::value>{};
using FooFooFoo = std::tuple<Foo, Foo, Foo>;
constexpr
auto fooEqFoo2 =
Term<std_get<0, FooFooFoo>, &Foo::value>{} == Term<std_get<1, FooFooFoo>, &Foo::value>{};
TEST_CASE("Term popCount") {
CHECK(2 == Term<&Aggregate::foo, &Foo::value, popCount>{}({Foo{"foo", 3}, {7}}));
CHECK_FALSE(Term<&Aggregate::foo, &Foo::value, popCount, isOdd>{}({Foo{"foo", 3}, {7}}));
CHECK(1 == Term<&Aggregate::foo, &Foo::value, popCount>{}({Foo{"foo", 2}, {7}}));
CHECK(Term<&Aggregate::foo, &Foo::value, popCount, isOdd>{}({Foo{"foo", 2}, {7}}));
}
TEST_CASE("Minterm") {
{ using MT = Minterm<
Term<&Foo::value, isOdd>,
Term<&Foo::value, popCount, isOdd>
>;
CHECK(MT({"", 0}).value == std::bitset<2>(0b00));
CHECK(MT({"", 1}).value == std::bitset<2>(0b11));
CHECK(MT({"", 2}).value == std::bitset<2>(0b10));
CHECK(MT({"", 3}).value == std::bitset<2>(0b01));
}
{ using MT = Minterm<
Term<&Aggregate::foo, &Foo::value, isOdd>,
Term<&Aggregate::foo, &Foo::value, popCount, isOdd>,
Term<&Aggregate::bar, &Bar::value, isEven>,
Term<&Aggregate::bar, &Bar::value, popCount, isEven>
>;
CHECK(MT({Foo{"", 0}, Bar{0}}).value == std::bitset<4>(0b1100));
CHECK(MT({Foo{"", 0}, Bar{1}}).value == std::bitset<4>(0b0000));
CHECK(MT({Foo{"", 0}, Bar{2}}).value == std::bitset<4>(0b0100));
CHECK(MT({Foo{"", 0}, Bar{3}}).value == std::bitset<4>(0b1000));
CHECK(MT({Foo{"", 1}, Bar{0}}).value == std::bitset<4>(0b1111));
CHECK(MT({Foo{"", 1}, Bar{1}}).value == std::bitset<4>(0b0011));
CHECK(MT({Foo{"", 1}, Bar{2}}).value == std::bitset<4>(0b0111));
CHECK(MT({Foo{"", 1}, Bar{3}}).value == std::bitset<4>(0b1011));
CHECK(MT({Foo{"", 2}, Bar{0}}).value == std::bitset<4>(0b1110));
CHECK(MT({Foo{"", 2}, Bar{1}}).value == std::bitset<4>(0b0010));
CHECK(MT({Foo{"", 2}, Bar{2}}).value == std::bitset<4>(0b0110));
CHECK(MT({Foo{"", 2}, Bar{3}}).value == std::bitset<4>(0b1010));
CHECK(MT({Foo{"", 3}, Bar{0}}).value == std::bitset<4>(0b1101));
CHECK(MT({Foo{"", 3}, Bar{1}}).value == std::bitset<4>(0b0001));
CHECK(MT({Foo{"", 3}, Bar{2}}).value == std::bitset<4>(0b0101));
CHECK(MT({Foo{"", 3}, Bar{3}}).value == std::bitset<4>(0b1001));
}
}
TEST_CASE("Equal") {
CHECK((Term<popCount>{} == Term<popCount>{})(13));
Foo foo { "foo", 5 };
Bar bar { 0 };
CHECK_FALSE(fooEqBar({foo, bar}));
CHECK_FALSE(fooEqFoo({foo, Foo{"foo2", 4}}));
CHECK(fooEqFoo2({Foo{"foo0", 0}, Foo{"foo1", 0}, Foo{"foo2", 0}}));
bar.value = 5;
CHECK(fooEqBar({foo, bar}));
CHECK(fooEqFoo({foo, Foo{"foo2", 5}}));
CHECK_FALSE(fooEqFoo2({Foo{"foo0", 0}, Foo{"foo1", 1}, Foo{"foo2", 2}}));
}