Last active
August 23, 2021 18:09
-
-
Save leocelente/c671e7fc8f63f985dea066208776c36d to your computer and use it in GitHub Desktop.
Snippets de C++ com várias abstrações - RAII, SFINAE - que compilam com custo zero em assembly; https://godbolt.org/z/31eh1q
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Compilar com o Compiler-Explorer -O1 | |
// https://godbolt.org/z/31eh1q | |
#include <type_traits> | |
/* BIBLIOTECA GENERICA*/ | |
template <class Lambda, class FunctorOpen, class FunctorClose, class... Args> | |
constexpr void wrap(Lambda l, FunctorOpen i, FunctorClose f, Args... p) { | |
i(p...); | |
l(); | |
f(p...); | |
} | |
template <class Lambda, class Functor, class... Args> // Variadic Template | |
constexpr void sandwich(Lambda l, Functor f, Args... p) { | |
wrap(l, f, f, p...); | |
} | |
//------------------------------------------ | |
/* BIBLIOTECA DO MICROCONTROLADOR | |
Tudo que mudaria de um micro pra outro seria a interface dessa `toogle_pin` | |
e os tipos dos `value` tem que bater com ela */ | |
extern void toggle_pin(int* port, unsigned int pin); | |
struct Port { | |
int* value; | |
}; | |
struct Pin { | |
unsigned int value; | |
}; | |
// Restringe que Type tem que ser Port | |
template <class Type> | |
using MustBePort = | |
std::enable_if_t<std::is_same<Type, Port>::value>; // Template | |
// Metaprogramming | |
// Restringe que Type tem que ser Pin | |
template <class Type> | |
using MustBePin = | |
std::enable_if_t<std::is_same<Type, Pin>::value>; // Template | |
// Metaprogramming | |
template <class PortType, class PinType, class Lambda, | |
typename = MustBePort<PortType>, // SFINAE | |
typename = MustBePin<PinType> // SFINAE | |
> | |
constexpr void toggle_hold(const PortType port, const PinType pin, Lambda l) { | |
sandwich( | |
/* Bloco de Código */ l, | |
/* Envolvido por */ toggle_pin, | |
/* Com argumentos */ port.value, pin.value); | |
} | |
extern void open_resource(void*); | |
extern void close_resource(void*); | |
extern void use_resource(void*); | |
// RAII | |
class ResourceHandler { | |
int* ptr; | |
public: | |
int* const get() const{ | |
return ptr; | |
} | |
ResourceHandler(int* p) : ptr(p) { open_resource(ptr); } | |
~ResourceHandler() { close_resource(ptr); } | |
// Copy, Move ctors auto deleted | |
}; | |
//----------------------------------------- | |
/* CODIGO NA APLICAÇAO */ | |
extern void SPI_Transmit(void); | |
int main() { | |
ResourceHandler hdlr{nullptr}; | |
constexpr Port peripheral_port{nullptr}; | |
constexpr Pin peripheral_pin{3u}; | |
/* Garante duas chamadas do toggle_pin | |
Garante que port e pin não sejam trocados */ | |
toggle_hold(peripheral_port, peripheral_pin, [&] { | |
SPI_Transmit(); | |
SPI_Transmit(); | |
// ... | |
SPI_Transmit(); | |
}); | |
/* NÃO COMPILA */ | |
// toggle_hold(peripheral_pin, peripheral_port, [&]{ | |
// SPI_Transmit(); | |
// }); | |
/* Compila :( */ | |
// int pin = 3; | |
// int port = 0; | |
// toggle_pin((int*)pin, port); /* se fosse toggle_pin(int,int) não precisaria do cast */ | |
// SPI_Transmit(); | |
// SPI_Transmit(); | |
// ... | |
use_resource(hdlr.get()); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment