spacebox/src/Switch.hpp

136 lines
3.9 KiB
C++

/* +------------------------------------------------------+
____/ \____ /| - Open source game framework licensed to freely use, |
\ / / | copy, modify and sell without restriction |
+--\ ^__^ /--+ | |
| ~/ \~ | | - created for <https://foam.shampoo.ooo> |
| ~~~~~~~~~~~~ | +------------------------------------------------------+
| SPACE ~~~~~ | /
| ~~~~~~~ BOX |/
+--------------+
A switch object contains a state of either on or off which can be read by reading the switch in a bool context. A
switch can be flipped to change the state. If a reaction function has been set, it will run every time the switch
is flipped. The function must accept a bool as its first argument which will provide the state of the switch. It can
also accept an arbitrary number of arguments after that and can return a value.
This example will flip the switch three times and print the state each time.
sb::Switch<> sw1;
sw1.on_state_change([](bool state) {
std::cout << "Door is " << (state ? "OPEN" : "CLOSED") << std::endl;
});
sw1.flip();
sw1.flip();
sw1.flip();
The expected output is
Door is OPEN
Door is CLOSED
Door is OPEN
This example ignores the switch state and adds an arbitrary amount to a running tally each flip.
sb::Switch<int, int, int> sw2;
sw2.on_state_change([](bool state, int tally, int add) -> int {
tally += add;
std::cout << "Adding " << add << " to tally: " << tally << std::endl;
return tally;
});
int tally = 0;
tally = sw2.flip(tally, 1);
tally = sw2.flip(tally, 5);
tally = sw2.flip(tally, 99);
The expected output is
Adding 1 to tally: 1
Adding 5 to tally: 6
Adding 99 to tally: 105
Although the state can just be ignored, it can also be forced to remain in one state. This example uses the
`&` operator to allow access to the switch itself so it can be turned off automatically after every flip.
sb::Switch<void, const std::string&> sw3;
sw3.on_state_change([&](bool state, const std::string& visitor) {
if (state)
{
std::cout << "Come in " << visitor << ", my door is always " << (state ? "OPEN" : "CLOSED") << std::endl;
sw3.flip("");
}
});
sw3.flip("Mario");
sw3.flip("Luigi");
sw3.flip("Toad");
The expected output is
Come in Mario, my door is always OPEN
Come in Luigi, my door is always OPEN
Come in Toad, my door is always OPEN
*/
#pragma once
#include <functional>
namespace sb
{
template<typename return_type = void, typename... arguments>
class Switch
{
private:
using Reaction = std::function<return_type(bool, arguments...)>;
inline static const bool STATE_OFF = false;
inline static const bool STATE_ON = true;
bool state = STATE_OFF;
Reaction reaction;
public:
/*!
* The switch object will initialized to the off state. A reaction function can be specified, otherwise it will have an
* empty reaction function.
*
* @param callback function to run on state change
*/
Switch(Reaction reaction = Reaction()) : reaction(reaction) {}
return_type flip(arguments... args)
{
state = !state;
return reaction(state, args...);
}
/*!
* Assign the reaction function.
*
* @param reaction function to be called when the state is changed
*/
void on_state_change(Reaction reaction)
{
this->reaction = reaction;
}
/*!
* @return true if state is Switch::STATE_ON, false otherwise
*/
bool on()
{
return state;
}
/*!
* @return when called as a boolean, return state
*/
operator bool()
{
return on();
}
};
}