#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 ////////////////
}
//==============================pass
struct pass
{
__forceinline template<class ...T>
constexpr pass(T...)
{
}
};
//====================================================
using namespace PinHelper ;
template <typename ...Ts>
struct PinsPack
{
using Pins = PinsPack<Ts...> ;
private:
using TPins = typename NoDuplicates<Collection<Ts...>>::Result;
static_assert(std::is_same<TPins, Collection<Ts...>>::value,
"Беда: Одинаковые пины в списке") ;
using Ports = typename
NoDuplicates<Collection<typename Ts::PortType...>>::Result;
template<class Q>
constexpr static auto GetPortValue(std::size_t mask)
{
std::size_t result = 0;
auto rmask = mask ;
pass{(result |= ((std::is_same<Q, typename Ts::PortType>::value ? 1 : 0) & mask) * (1 << Ts::pin), mask>>=1)...};
pass{(result |= ((std::is_same<Q, typename Ts::PortType>::value ? 1 : 0) & ~rmask) * ((1 << Ts::pin) << 16), rmask>>=1)...};
return result;
}
__forceinline template<typename Port, typename ...Ports>
constexpr static void SetPorts(Collection<Port, Ports...>, std::size_t mask)
{
auto result = GetPortValue<Port>(mask) ;
Port::Set(result & 0xff) ;
if constexpr (sizeof ...(Ports) != 0U)
{
Pins::template SetPorts<Ports...>(Collection<Ports...>(), mask) ;
}
}
__forceinline template<std::size_t mask, typename Port, typename ...Ports>
constexpr static void SetPorts(Collection<Port, Ports...>)
{
constexpr auto result = GetPortValue<Port>(mask) ;
Port::Set(result & 0xff) ;
if constexpr (sizeof ...(Ports) != 0U)
{
Pins::template SetPorts<mask, Ports...>(Collection<Ports...>()) ;
}
}
__forceinline template<typename Port, typename ...Ports>
constexpr static void WritePorts(Collection<Port, Ports...>, std::size_t mask)
{
Port::Set(GetPortValue<Port>(mask)) ;
if constexpr (sizeof ...(Ports) != 0U)
{
Pins::template WritePorts<Ports...>(Collection<Ports...>(), mask) ;
}
}
__forceinline template<std::size_t mask, typename Port, typename ...Ports>
constexpr static void WritePorts(Collection<Port, Ports...>)
{
Port::Set(GetPortValue<Port>(mask)) ;
if constexpr (sizeof ...(Ports) != 0U)
{
Pins::template WritePorts<mask, Ports...>(Collection<Ports...>()) ;
}
}
public:
static constexpr size_t size = sizeof ...(Ts) + 1U ;
__forceinline static void Set(std::size_t mask )
{
SetPorts(Ports(), mask) ;
}
__forceinline template<std::size_t mask = 0xffffffffU>
static void Set()
{
SetPorts<mask>(Ports()) ;
}
__forceinline static void Write(std::size_t mask)
{
WritePorts(Ports(), mask) ;
}
__forceinline template<std::size_t mask = 0xffffffffU>
static void Write()
{
WritePorts<mask>(Ports()) ;
}
} ;
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>::Set() ;
std::cout << " " << std::endl ;
PinsPack<Pin1, Pin2, Pin3, Pin4, Pin5>::Write(7) ;
//std::cout << PinsPack<Pin1, Pin2, Pin3, Pin4, Pin5>::size << std::endl ;
PinsPack<Pin1, Pin2, Pin3, Pin4, Pin5>::Write('A') ;
using PinList = Collection<Pin1, Pin2, Pin3, Pin4> ;
using TPins = typename NoDuplicates<PinList>::Result;
static_assert(std::is_same<TPins, PinList>::value,
" Беда: Одинаковые пины в списке ") ;
return 0;
}