spacebox/src/Connection.hpp

147 lines
5.0 KiB
C++

/* /\ +------------------------------------------------------+
* ____/ \____ /| - Open source game framework licensed to freely use, |
* \ / / | copy, modify and sell without restriction |
* +--\ ^__^ /--+ | |
* | ~/ \~ | | - created for <https://foam.shampoo.ooo> |
* | ~~~~~~~~~~~~ | +------------------------------------------------------+
* | SPACE ~~~~~ | /
* | ~~~~~~~ BOX |/
* +--------------+
*
* Connection
* ==========
*
* A connection is an object containing a binary state of either on (connected) or off (not connected)
* and user supplied functions that run automatically on each state change. The functions each have the
* same return type, number of arguments, and argument types determined by the template arguments.
*
* Original test code:
*
* Connection<> connection_d(std::bind(&Game::print_frame_length_history, this));
* connection_d.toggle();
* Connection<int, int, int> connection_f {
* std::function<int(int, int)>(&sb::mod), std::function<int(int, int)>(&sb::mod) };
* Connection<> connection_g = connection_d;
* connection_g.toggle();
* connection_g.disconnect();
* int result;
* result = connection_f.connect(3, 5);
* std::cout << result << " ";
* std::cout << connection_f.disconnect(20, 6) << " ";
* result = connection_f.toggle(800, 120);
* std::cout << result << std::endl;
* result = connection_f.connect(111, 44);
* std::cout << result << std::endl;
*/
#include <functional>
namespace sb
{
template<typename return_type = void, typename... arguments>
class Connection
{
private:
enum State : bool
{
STATE_OFF,
STATE_ON
};
using callback = std::function<return_type(arguments...)>;
State connection_state = STATE_OFF;
callback on_connect_callback, on_disconnect_callback;
public:
/* Without any arguments, the connection object will be in the disconnected state with empty functions. Otherwise,
* the supplied functions will be added to the connection object. The first function argument will be run on a
* connection, and the second function argument will be run on a disconnection. */
Connection(callback on_connect_callback = callback(), callback on_disconnect_callback = callback())
{
if (on_connect_callback)
{
on_connect(on_connect_callback);
if (on_disconnect_callback)
{
on_disconnect(on_disconnect_callback);
}
}
}
/* Set the function that will run when a connection is made. */
void on_connect(callback on_connect)
{
on_connect_callback = on_connect;
}
/* Set the function that will run when a disconnection happens. */
void on_disconnect(callback on_disconnect)
{
on_disconnect_callback = on_disconnect;
}
/* Set state to Connection::STATE_ON and run response function. If return_type is non-void and the
* connection is already connected, the function will not run and the return value will be a default
* constructed value of the type return_type. Therefore, return_type must be default constructible. */
return_type connect(arguments... args)
{
if (!*this)
{
connection_state = STATE_ON;
if (on_connect_callback)
{
return on_connect_callback(args...);
}
}
return return_type();
}
/* Set state to Connection::STATE_OFF and run response function. If return_type is non-void and the
* connection is already disconnected, the function will not run and the return value will be a default
* constructed value of the type return_type. Therefore, return_type must be default constructible. */
return_type disconnect(arguments... args)
{
if (*this)
{
connection_state = STATE_OFF;
if (on_disconnect_callback)
{
return on_disconnect_callback(args...);
}
}
return return_type();
}
/* Set state to the opposite of current state, causing the appropriate response function to run. */
return_type toggle(arguments... args)
{
if (*this)
{
return disconnect(args...);
}
else
{
return connect(args...);
}
}
/* Return true if state is Connection::STATE_ON, false otherwise. */
bool connected()
{
return connection_state;
}
/* When called as a boolean, return the connection state. */
operator bool()
{
return connected();
}
};
}