Sometimes you need to do things when a condition changes, here is a simple class to keep track of the state of the last call and execute callbacks when the state changes.
#include <functional>
#include <cassert>
/// latch is a class that contains of a test function and a couple of callbacks, when the return
/// value of the test function changes the approrpiate callback gets called, as long as the return
/// value of the test function stays the same no callbacks will be called. Callbacks may be nullptr
template<class...Args>
class Latch {
public:
Latch(std::function<bool(Args ...)> shouldLatch, std::function<void(Args...)> onLatch = nullptr, std::function<void(Args...)> onUnlatch = nullptr) :
m_shouldLatch(std::move(shouldLatch)),
m_onLatch(std::move(onLatch)),
m_onUnlatch(std::move(onUnlatch)) {}
bool latched() const noexcept { return m_isLatched; }
explicit operator bool() const noexcept { return m_isLatched; }
void update(Args&& ... args)
{
if (m_shouldLatch && m_isLatched != m_shouldLatch(std::forward<Args>(args)... ))
{
m_isLatched = !m_isLatched;
auto& call = (m_isLatched) ? m_onLatch : m_onUnlatch;
if (call) call(std::forward<Args>(args)...);
}
}
private:
bool m_isLatched = false;
std::function<bool(Args ...)> m_shouldLatch;
std::function<void(Args ...)> m_onLatch;
std::function<void(Args ...)> m_onUnlatch;
};
int main()
{
int onLatch = 0;
int onUnlatch = 0;
int latchVal = 1;
Latch<int> l1([&latchVal](auto val){return val == latchVal;},
[&onLatch](auto val){++onLatch;},
[&onUnlatch](auto val){++onUnlatch;});
assert(!l1);
l1.update(0);
assert(!l1);
assert(onLatch == 0 && onUnlatch == 0);
l1.update(1);
assert(l1.latched());
assert(onLatch == 1 && onUnlatch == 0);
l1.update(1);
assert(onLatch == 1 && onUnlatch == 0);
l1.update(0);
assert(onLatch == 1 && onUnlatch == 1);
Latch l2 = l1;
}
This is also at https://www.godbolt.org/z/z4b934
Thanks for the input