#include <cstdint>
#include <type_traits>
#include <iostream>
#include <initializer_list>
#define __forceinline _Pragma("inline=forced")
struct GPIOA
{
static void Set(std::uint32_t value)
{
std::cout << "PortA:" << value << std::endl ;
}
} ;
struct GPIOC
{
static void Set(std::uint32_t value)
{
std::cout << "PortC:" << value << std::endl ; ;
}
} ;
struct GPIOB
{
static void Set(std::uint32_t value)
{
std::cout << "PortB:" << value << std::endl ; ;
}
} ;
template <typename T, std::uint32_t pinNum>
struct Pin
{
using PortType = T ;
constexpr static std::uint32_t pin = pinNum ;
} ;
namespace PinHelper
{
template<typename ... Types> struct Collection
{
// static constexpr int size = (sizeof...(Types));
};
///////////////// Заимствуем идею NoDuplicates из библиотеки LOKI ////////////////
template<class X, class Y> struct Glue;
template<class T, class... Ts>
struct Glue<T, Collection<Ts...>> {
using Result = Collection<T, Ts...>;};
template<class Q, class X> struct Erase;
template<class Q>
struct Erase<Q, Collection<>> {
using Result = Collection<>;};
template<class Q, class... Tail>
struct Erase<Q, Collection<Q, Tail...>> {
using Result = Collection<Tail...>;};
template<class Q, class T, class... Tail>
struct Erase<Q, Collection<T, Tail...>> {
using Result = typename Glue<T, typename Erase<Q, Collection<Tail...>>::Result>::Result;};
template <class X> struct NoDuplicates;
template <> struct NoDuplicates<Collection<>>
{
using Result = Collection<>;
};
template <class T, class... Tail>
struct NoDuplicates< Collection<T, Tail...> >
{
private:
using L1 = typename NoDuplicates<Collection<Tail...>>::Result;
using L2 = typename Erase<T,L1>::Result;
public:
using Result = typename Glue<T, L2>::Result;
};
///////////////// LOKI ////////////////
}
//==============================GetValue
template <typename Type, typename ...Ts>
struct PinsPack ;
template <typename QueriedPort, typename Type, typename ...Ts>
constexpr static auto GetValue(PinsPack<Type, Ts...>, std::size_t value)
{
std::size_t result = 0U;
if constexpr (sizeof ...(Ts) != 0U)
{
using MyPins = PinsPack<Ts...> ;
if ((std::is_same<typename Type::PortType, QueriedPort>::value) && ((value & 1U) == 1U))
{
result = ((1U << Type::pin) | (GetValue<QueriedPort>(MyPins(), (value >> 1U) ))) ;
}
else if ((std::is_same<typename Type::PortType, QueriedPort>::value) && ((value & 1U) != 1U))
{
result = (((1U << Type::pin) << 16) | (GetValue<QueriedPort>(MyPins(), (value >> 1U) ))) ;
}
else
{
result = GetValue<QueriedPort>(MyPins(), (value >> 1U)) ;
}
}
else
{
using MyPins = PinsPack<Type> ;
if ((std::is_same<typename Type::PortType, QueriedPort>::value) && (value & 1U) == 1U)
{
result = (1U << Type::pin) ;
}
else if ((std::is_same<typename Type::PortType, QueriedPort>::value) && (value & 1U) != 1U)
{
result = (1U << Type::pin) << 16U;
}
else
{
result = 0U;
}
}
return result ;
}
//====================================================
using namespace PinHelper ;
template <typename Type, typename ...Ts>
struct PinsPack
{
using Pins = PinsPack<Type,Ts...> ;
private:
constexpr static auto CreatePortList()
{
using TPins = typename NoDuplicates<Collection<Type, Ts...>>::Result;
static_assert(std::is_same<TPins, Collection<Type,Ts...>>::value, "Одинаковые пины в списке") ;
using Ports = typename NoDuplicates<Collection<typename Type::PortType, typename Ts::PortType...>>::Result;
return Ports();
}
__forceinline template<typename Port, typename ...Ports>
constexpr static void SetPorts(Collection<Port, Ports...>, std::uint32_t value)
{
using MyPins = PinsPack<Type, Ts...> ;
uint32_t result = GetValue<Port>(MyPins(), value) ;
Port::Set(result & 0xff) ;
if constexpr (sizeof ...(Ports) != 0U)
{
MyPins::template SetPorts<Ports...>(Collection<Ports...>(), value) ;
}
}
__forceinline template<typename Port, typename ...Ports>
constexpr static void SetAndResetPorts(Collection<Port, Ports...>, std::uint32_t value)
{
using MyPins = PinsPack<Type, Ts...> ;
uint32_t result = GetValue<Port>(MyPins(), value) ;
//uint32_t result1 = GetValue<Port>(MyPins(), ((~value) & ((1 << size) - 1))) ;
Port::Set(result) ;
if constexpr (sizeof ...(Ports) != 0U)
{
MyPins::template SetAndResetPorts<Ports...>(Collection<Ports...>(), value) ;
}
}
public:
static constexpr size_t size = sizeof ...(Ts) + 1U ;
__forceinline static void Set(std::size_t value = 0xffffffffU )
{
SetPorts(CreatePortList(), value) ;
}
__forceinline static void SetAndReset(std::size_t value = 0xffffffffU )
{
SetAndResetPorts(CreatePortList(), value) ;
}
} ;
using Pin1 = Pin<GPIOC, 1>;
using Pin2 = Pin<GPIOB, 1>;
using Pin3 = Pin<GPIOA, 1>;
using Pin4 = Pin<GPIOC, 2>;
using Pin5 = Pin<GPIOA, 3>;
int main()
{
PinsPack<Pin1, Pin2, Pin3, Pin4, Pin5>::Set() ;
std::cout << " " << std::endl ;
PinsPack<Pin1, Pin2, Pin3, Pin4, Pin5>::Set(3) ;
std::cout << " " << std::endl ;
PinsPack<Pin1, Pin2, Pin3, Pin4, Pin5>::SetAndReset(7) ;
//std::cout << PinsPack<Pin1, Pin2, Pin3, Pin4, Pin5>::size << std::endl ;
using PinList = Collection<Pin1, Pin2, Pin3, Pin4> ;
using TPins = typename NoDuplicates<PinList>::Result;
static_assert(std::is_same<TPins, PinList>::value, "Одинаковые пины в списке") ;
return 0;
}