162 lines
4.8 KiB
C++
162 lines
4.8 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>
|
|
#include <ostream>
|
|
|
|
namespace sb
|
|
{
|
|
template<typename return_type = void, typename... arguments>
|
|
class Switch
|
|
{
|
|
|
|
private:
|
|
|
|
using Reaction = std::function<return_type(bool, arguments...)>;
|
|
|
|
bool state = false;
|
|
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) {}
|
|
|
|
Switch(bool state, Reaction reaction = Reaction()) : state(state), reaction(reaction) {}
|
|
|
|
/*!
|
|
* Toggle state, triggering the reaction function.
|
|
*
|
|
* @param args arbitrary list of arguments that are expected by the reaction function
|
|
* @return return the return value of the reaction function
|
|
*/
|
|
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 when called as a boolean, return state
|
|
*/
|
|
operator bool() const
|
|
{
|
|
return state;
|
|
}
|
|
|
|
/*!
|
|
* Assign the switch object's state using the assignment operator with a boolean value, without triggering the reaction function.
|
|
* To trigger the reaction function, use `Switch::flip` instead.
|
|
*
|
|
* @param state state the switch will be set to
|
|
*/
|
|
Switch<return_type, arguments...>& operator=(bool state)
|
|
{
|
|
this->state = state;
|
|
return *this;
|
|
}
|
|
|
|
operator std::string() const
|
|
{
|
|
return state ? "true" : "false";
|
|
}
|
|
|
|
};
|
|
}
|
|
|
|
namespace std
|
|
{
|
|
template<typename return_type, typename... arguments>
|
|
std::ostream& operator<<(std::ostream& stream, const sb::Switch<return_type, arguments...>& sw)
|
|
{
|
|
stream << std::string(sw);
|
|
return stream;
|
|
}
|
|
}
|