Possible addition: Timer::callOnCondition


#1

In the process of tidying up a class where I need to execute some code once a condition becomes true (which needs to be checked at a given interval - GPIO input on a Raspberry Pi), inspired by (and based on) the Timer::callAfterDelay method I wrote this:

struct TimerExtensions
{
    struct LambdaConditionalInvoker : private Timer
    {
        LambdaConditionalInvoker (std::function<bool ()> c, std::function<void ()> f, int interval)
                : function (f), condition (c)
        {
            startTimer (interval);
        }

        void timerCallback () override
        {
            if (condition ())
            {
                auto f = function;
                delete this;
                f ();
            }
        }

        std::function<void ()> function;
        std::function<bool ()> condition;

        JUCE_DECLARE_NON_COPYABLE (LambdaConditionalInvoker)
    };

    static void callOnCondition (std::function<bool ()> c, std::function<void ()> f, int interval = 50)
    {
        new LambdaConditionalInvoker (c, f, interval);
    }
};

I don’t know if its useful enough to warrant going into the Timer class but it might be useful to someone else.

Example usage:

TimerExtensions::callOnCondition ([&]
{
    return (checkConditionIsZero() == 0);
},
[this]
{
    methodToCall();
});

Button::onClick
#2

So I painted myself into a corner here - we needed to be able to abort timers, and there were timer objects getting left hanging in memory, and trying to delete them without causing BAD ACCESS exceptions was proving difficult. So I removed all pointer stuff and used a std::list to keep track of all the timers. Again, maybe this is useful to someone:

#include "JuceHeader.h"
#include <list>

class ConditionalTimers
{
public:
    ~ConditionalTimers()
    {
        clear();
    }

    void clear()
    {
        conditionalTimers.clear();
    }

    struct LambdaConditionalInvoker : private Timer
    {
        LambdaConditionalInvoker (std::function<bool()> c, std::function<void()> f, int interval)
                : function (f), condition (c)
        {
            startTimer (interval);
        }

        ~LambdaConditionalInvoker()
        {
            stop();
        }

        void timerCallback() override
        {
            if (condition())
            {
                auto f = function;
                stopTimer();
                f();
            }
        }

        void stop()
        {
            if (isTimerRunning()) stopTimer();
        }

        std::function<void ()> function;
        std::function<bool ()> condition;

        JUCE_DECLARE_NON_COPYABLE (LambdaConditionalInvoker)
    };

    void callOnCondition (std::function<bool ()> c, std::function<void ()> f, int interval = 50)
    {
        conditionalTimers.emplace_back (c, f, interval);
    }

private:
    std::list<ConditionalTimers::LambdaConditionalInvoker> conditionalTimers;

};

Usage:

conditionalTimers.callOnCondition ([&]
{
    return (checkConditionIsZero() == 0);
},
[this]
{
    methodToCall();
});

//.....
// To stop / clear all timers:
conditionalTimers.clear();


// Member variables:
ConditionalTimers conditionalTimers;