Async addition to ListenerList


#1

What do you think on this one ? Something on the line of this could be added to the library… i find it very useful in case i need to mix sync/async listener callbacks from different scenarios.

template <class ListenerClass,
          class ArrayType = juce::Array<ListenerClass*> >
class AsyncListenerList
{
    // Horrible macros required to support VC7..
    #ifndef DOXYGEN
     #if JUCE_VC8_OR_EARLIER
       #define LL_TEMPLATE(a)   typename P##a, typename Q##a
       #define LL_PARAM(a)      Q##a& param##a
     #else
       #define LL_TEMPLATE(a)   typename P##a
       #define LL_PARAM(a)      typename juce::TypeHelpers::ParameterType<P##a>::type param##a
     #endif
    #endif

public:
    typedef AsyncListenerList<ListenerClass, ArrayType> ThisType;
    typedef ListenerClass ListenerType;

    //==============================================================================
    /** Creates an empty list. */
    AsyncListenerList()
    {
    }

    /** Destructor. */
    ~AsyncListenerList()
    {
        masterReference.clear();
    }

    //==============================================================================
    /** Adds a listener to the list.
        A listener can only be added once, so if the listener is already in the list,
        this method has no effect.
        @see remove
    */
    void add (ListenerClass* const listenerToAdd)
    {
        // Listeners can't be null pointers!
        jassert (listenerToAdd != nullptr);

        const juce::ScopedLock sl (listenerLock);

        if (listenerToAdd != nullptr)
            listeners.addIfNotAlreadyThere (listenerToAdd);
    }

    /** Removes a listener from the list.
        If the listener wasn't in the list, this has no effect.
    */
    void remove (ListenerClass* const listenerToRemove)
    {
        // Listeners can't be null pointers!
        jassert (listenerToRemove != nullptr);

        const juce::ScopedLock sl (listenerLock);

        listeners.removeFirstMatchingValue (listenerToRemove);
    }

    /** Returns the number of registered listeners. */
    int size() const noexcept
    {
        const juce::ScopedLock sl (listenerLock);

        return listeners.size();
    }

    /** Returns true if any listeners are registered. */
    bool isEmpty() const noexcept
    {
        const juce::ScopedLock sl (listenerLock);

        return listeners.size() == 0;
    }

    /** Clears the list. */
    void clear()
    {
        const juce::ScopedLock sl (listenerLock);

        listeners.clear();
    }

    /** Returns true if the specified listener has been added to the list. */
    bool contains (ListenerClass* const listener) const noexcept
    {
        const juce::ScopedLock sl (listenerLock);

        return listeners.contains (listener);
    }

    //==============================================================================
    /** Calls a member function on each listener in the list, with no parameters. */
    void call (void (ListenerClass::*callbackFunction) ())
    {
        callChecked (static_cast <const DummyBailOutChecker&> (DummyBailOutChecker()), callbackFunction);
    }

    /** Calls a member function on each listener in the list, with no parameters and a bail-out-checker.
        See the class description for info about writing a bail-out checker. */
    template <class BailOutCheckerType>
    void callChecked (const BailOutCheckerType& bailOutChecker,
                      void (ListenerClass::*callbackFunction) ())
    {
        const juce::ScopedLock sl (listenerLock);

        for (Iterator<BailOutCheckerType, ThisType> iter (*this); iter.next (bailOutChecker);)
            (iter.getListener()->*callbackFunction) ();
    }

    //==============================================================================
    template <class BailOutCheckerType>
    class CallbackMessage0 : public juce::MessageManager::MessageBase
    {
    public:
        CallbackMessage0 (const ThisType* all,
                          const BailOutCheckerType& bailOutChecker,
                          void (ListenerClass::*callbackFunction) ()) noexcept
            : listenerList (const_cast<ThisType*> (all)),
            bailOutChecker (bailOutChecker),
            callback (callbackFunction)
        {}

        void messageCallback() override
        {
            if (const ThisType* const all = listenerList)
                listenerList->callChecked(bailOutChecker, callback);
        }

    private:
        juce::WeakReference<ThisType> listenerList;
        const BailOutCheckerType& bailOutChecker;
        void (ListenerClass::*callback) ();

        JUCE_DECLARE_NON_COPYABLE (CallbackMessage0)
    };

    void callAsync (void (ListenerClass::*callbackFunction) ())
    {
        (new CallbackMessage0<DummyBailOutChecker>
            (this, static_cast <const DummyBailOutChecker&> (DummyBailOutChecker()), callbackFunction))->post();
    }

    template <class BailOutCheckerType>
    void callAsyncChecked (const BailOutCheckerType& bailOutChecker,
                           void (ListenerClass::*callbackFunction) ())
    {
        (new CallbackMessage0<BailOutCheckerType>
            (this, bailOutChecker, callbackFunction))->post();
    }

    //==============================================================================
    /** Calls a member function on each listener in the list, with 1 parameter. */
    template <LL_TEMPLATE(1)>
    void call (void (ListenerClass::*callbackFunction) (P1), LL_PARAM(1))
    {
        for (Iterator<DummyBailOutChecker, ThisType> iter (*this); iter.next();)
            (iter.getListener()->*callbackFunction) (param1);
    }

    /** Calls a member function on each listener in the list, with one parameter and a bail-out-checker.
        See the class description for info about writing a bail-out checker. */
    template <class BailOutCheckerType, LL_TEMPLATE(1)>
    void callChecked (const BailOutCheckerType& bailOutChecker,
                      void (ListenerClass::*callbackFunction) (P1),
                      LL_PARAM(1))
    {
        for (Iterator<BailOutCheckerType, ThisType> iter (*this); iter.next (bailOutChecker);)
            (iter.getListener()->*callbackFunction) (param1);
    }

    //==============================================================================
    template <class BailOutCheckerType, LL_TEMPLATE(1)>
    class CallbackMessage1 : public juce::MessageManager::MessageBase
    {
    public:
        CallbackMessage1 (const ThisType* all,
                          const BailOutCheckerType& bailOutChecker,
                          void (ListenerClass::*callbackFunction) (P1),
                          LL_PARAM(1)) noexcept
            : listenerList (const_cast<ThisType*> (all)),
            bailOutChecker (bailOutChecker),
            callback (callbackFunction),
            param1 (param1)
        {}

        void messageCallback() override
        {
            if (const ThisType* const all = listenerList)
                listenerList->callChecked(bailOutChecker, callback, param1);
        }

    private:
        juce::WeakReference<ThisType> listenerList;
        const BailOutCheckerType& bailOutChecker;
        void (ListenerClass::*callback) (P1);
        LL_PARAM(1);

        JUCE_DECLARE_NON_COPYABLE (CallbackMessage1)
    };

    template <LL_TEMPLATE(1)>
    void callAsync (void (ListenerClass::*callbackFunction) (P1), LL_PARAM(1))
    {
        (new CallbackMessage1<DummyBailOutChecker, P1>
            (this, static_cast <const DummyBailOutChecker&> (DummyBailOutChecker()), callbackFunction, param1))->post();
    }

    template <class BailOutCheckerType, LL_TEMPLATE(1)>
    void callAsyncChecked (const BailOutCheckerType& bailOutChecker,
                           void (ListenerClass::*callbackFunction) (P1),
                           LL_PARAM(1))
    {
        (new CallbackMessage1<BailOutCheckerType, P1>
            (this, bailOutChecker, callbackFunction, param1))->post();
    }

    //==============================================================================
    /** Calls a member function on each listener in the list, with 2 parameters. */
    template <LL_TEMPLATE(1), LL_TEMPLATE(2)>
    void call (void (ListenerClass::*callbackFunction) (P1, P2),
               LL_PARAM(1), LL_PARAM(2))
    {
        for (Iterator<DummyBailOutChecker, ThisType> iter (*this); iter.next();)
            (iter.getListener()->*callbackFunction) (param1, param2);
    }

    /** Calls a member function on each listener in the list, with 2 parameters and a bail-out-checker.
        See the class description for info about writing a bail-out checker. */
    template <class BailOutCheckerType, LL_TEMPLATE(1), LL_TEMPLATE(2)>
    void callChecked (const BailOutCheckerType& bailOutChecker,
                      void (ListenerClass::*callbackFunction) (P1, P2),
                      LL_PARAM(1), LL_PARAM(2))
    {
        for (Iterator<BailOutCheckerType, ThisType> iter (*this); iter.next (bailOutChecker);)
            (iter.getListener()->*callbackFunction) (param1, param2);
    }

    //==============================================================================
    template <class BailOutCheckerType, LL_TEMPLATE(1), LL_TEMPLATE(2)>
    class CallbackMessage2 : public juce::MessageManager::MessageBase
    {
    public:
        CallbackMessage2 (const ThisType* all,
                          const BailOutCheckerType& bailOutChecker,
                          void (ListenerClass::*callbackFunction) (P1, P2),
                          LL_PARAM(1), LL_PARAM(2)) noexcept
            : listenerList (const_cast<ThisType*> (all)),
            bailOutChecker (bailOutChecker),
            callback (callbackFunction),
            param1 (param1),
            param2 (param2)
        {}

        void messageCallback() override
        {
            if (const ThisType* const all = listenerList)
                listenerList->callChecked(bailOutChecker, callback, param1, param2);
        }

    private:
        juce::WeakReference<ThisType> listenerList;
        const BailOutCheckerType& bailOutChecker;
        void (ListenerClass::*callback) (P1, P2);
        LL_PARAM(1);
        LL_PARAM(2);

        JUCE_DECLARE_NON_COPYABLE (CallbackMessage2)
    };

    template <LL_TEMPLATE(1), LL_TEMPLATE(2)>
    void callAsync (void (ListenerClass::*callbackFunction) (P1, P2), LL_PARAM(1), LL_PARAM(2))
    {
        (new CallbackMessage2<DummyBailOutChecker, P1, P2>
            (this, static_cast <const DummyBailOutChecker&> (DummyBailOutChecker()), callbackFunction, param1, param2))->post();
    }

    template <class BailOutCheckerType, LL_TEMPLATE(1), LL_TEMPLATE(2)>
    void callAsyncChecked (const BailOutCheckerType& bailOutChecker,
                           void (ListenerClass::*callbackFunction) (P1, P2),
                           LL_PARAM(1), LL_PARAM(2))
    {
        (new CallbackMessage2<BailOutCheckerType, P1, P2>
            (this, bailOutChecker, callbackFunction, param1, param2))->post();
    }

    //==============================================================================
    /** Calls a member function on each listener in the list, with 3 parameters. */
    template <LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3)>
    void call (void (ListenerClass::*callbackFunction) (P1, P2, P3),
               LL_PARAM(1), LL_PARAM(2), LL_PARAM(3))
    {
        for (Iterator<DummyBailOutChecker, ThisType> iter (*this); iter.next();)
            (iter.getListener()->*callbackFunction) (param1, param2, param3);
    }

    /** Calls a member function on each listener in the list, with 3 parameters and a bail-out-checker.
        See the class description for info about writing a bail-out checker. */
    template <class BailOutCheckerType, LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3)>
    void callChecked (const BailOutCheckerType& bailOutChecker,
                      void (ListenerClass::*callbackFunction) (P1, P2, P3),
                      LL_PARAM(1), LL_PARAM(2), LL_PARAM(3))
    {
        for (Iterator<BailOutCheckerType, ThisType> iter (*this); iter.next (bailOutChecker);)
            (iter.getListener()->*callbackFunction) (param1, param2, param3);
    }

    //==============================================================================
    template <class BailOutCheckerType, LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3)>
    class CallbackMessage3 : public juce::MessageManager::MessageBase
    {
    public:
        CallbackMessage3 (const ThisType* all,
                          const BailOutCheckerType& bailOutChecker,
                          void (ListenerClass::*callbackFunction) (P1, P2, P3),
                          LL_PARAM(1), LL_PARAM(2), LL_PARAM(3)) noexcept
            : listenerList (const_cast<ThisType*> (all)),
            bailOutChecker (bailOutChecker),
            callback (callbackFunction),
            param1 (param1),
            param2 (param2),
            param3 (param3)
        {}

        void messageCallback() override
        {
            if (const ThisType* const all = listenerList)
                listenerList->callChecked(bailOutChecker, callback, param1, param2, param3);
        }

    private:
        juce::WeakReference<ThisType> listenerList;
        const BailOutCheckerType& bailOutChecker;
        void (ListenerClass::*callback) (P1, P2, P3);
        LL_PARAM(1);
        LL_PARAM(2);
        LL_PARAM(3);

        JUCE_DECLARE_NON_COPYABLE (CallbackMessage3)
    };

    template <LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3)>
    void callAsync (void (ListenerClass::*callbackFunction) (P1, P2, P3), LL_PARAM(1), LL_PARAM(2), LL_PARAM(3))
    {
        (new CallbackMessage3<DummyBailOutChecker, P1, P2, P3>
            (this, static_cast <const DummyBailOutChecker&> (DummyBailOutChecker()), callbackFunction, param1, param2, param3))->post();
    }

    template <class BailOutCheckerType, LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3)>
    void callAsyncChecked (const BailOutCheckerType& bailOutChecker,
                           void (ListenerClass::*callbackFunction) (P1, P2, P3),
                           LL_PARAM(1), LL_PARAM(2), LL_PARAM(3))
    {
        (new CallbackMessage3<BailOutCheckerType, P1, P2, P3>
            (this, bailOutChecker, callbackFunction, param1, param2, param3))->post();
    }

    //==============================================================================
    /** Calls a member function on each listener in the list, with 4 parameters. */
    template <LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3), LL_TEMPLATE(4)>
    void call (void (ListenerClass::*callbackFunction) (P1, P2, P3, P4),
               LL_PARAM(1), LL_PARAM(2), LL_PARAM(3), LL_PARAM(4))
    {
        for (Iterator<DummyBailOutChecker, ThisType> iter (*this); iter.next();)
            (iter.getListener()->*callbackFunction) (param1, param2, param3, param4);
    }

    /** Calls a member function on each listener in the list, with 4 parameters and a bail-out-checker.
        See the class description for info about writing a bail-out checker. */
    template <class BailOutCheckerType, LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3), LL_TEMPLATE(4)>
    void callChecked (const BailOutCheckerType& bailOutChecker,
                      void (ListenerClass::*callbackFunction) (P1, P2, P3, P4),
                      LL_PARAM(1), LL_PARAM(2), LL_PARAM(3), LL_PARAM(4))
    {
        for (Iterator<BailOutCheckerType, ThisType> iter (*this); iter.next (bailOutChecker);)
            (iter.getListener()->*callbackFunction) (param1, param2, param3, param4);
    }

    //==============================================================================
    template <class BailOutCheckerType, LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3), LL_TEMPLATE(4)>
    class CallbackMessage4 : public juce::MessageManager::MessageBase
    {
    public:
        CallbackMessage4 (const ThisType* all,
                          const BailOutCheckerType& bailOutChecker,
                          void (ListenerClass::*callbackFunction) (P1, P2, P3, P4),
                          LL_PARAM(1), LL_PARAM(2), LL_PARAM(3), LL_PARAM(4)) noexcept
            : listenerList (const_cast<ThisType*> (all)),
            bailOutChecker (bailOutChecker),
            callback (callbackFunction),
            param1 (param1),
            param2 (param2),
            param3 (param3),
            param4 (param4)
        {}

        void messageCallback() override
        {
            if (const ThisType* const all = listenerList)
                listenerList->callChecked(bailOutChecker, callback, param1, param2, param3, param4);
        }

    private:
        juce::WeakReference<ThisType> listenerList;
        const BailOutCheckerType& bailOutChecker;
        void (ListenerClass::*callback) (P1, P2, P3, P4);
        LL_PARAM(1);
        LL_PARAM(2);
        LL_PARAM(3);
        LL_PARAM(4);

        JUCE_DECLARE_NON_COPYABLE (CallbackMessage4)
    };

    template <LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3), LL_TEMPLATE(4)>
    void callAsync (void (ListenerClass::*callbackFunction) (P1, P2, P3, P4), LL_PARAM(1), LL_PARAM(2), LL_PARAM(3), LL_PARAM(4))
    {
        (new CallbackMessage4<DummyBailOutChecker, P1, P2, P3, P4>
            (this, static_cast <const DummyBailOutChecker&> (DummyBailOutChecker()), callbackFunction, param1, param2, param3, param4))->post();
    }

    template <class BailOutCheckerType, LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3), LL_TEMPLATE(4)>
    void callAsyncChecked (const BailOutCheckerType& bailOutChecker,
                           void (ListenerClass::*callbackFunction) (P1, P2, P3, P4),
                           LL_PARAM(1), LL_PARAM(2), LL_PARAM(3), LL_PARAM(4))
    {
        (new CallbackMessage4<BailOutCheckerType, P1, P2, P3, P4>
            (this, bailOutChecker, callbackFunction, param1, param2, param3, param4))->post();
    }

    //==============================================================================
    /** Calls a member function on each listener in the list, with 5 parameters. */
    template <LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3), LL_TEMPLATE(4), LL_TEMPLATE(5)>
    void call (void (ListenerClass::*callbackFunction) (P1, P2, P3, P4, P5),
               LL_PARAM(1), LL_PARAM(2), LL_PARAM(3), LL_PARAM(4), LL_PARAM(5))
    {
        for (Iterator<DummyBailOutChecker, ThisType> iter (*this); iter.next();)
            (iter.getListener()->*callbackFunction) (param1, param2, param3, param4, param5);
    }

    /** Calls a member function on each listener in the list, with 5 parameters and a bail-out-checker.
        See the class description for info about writing a bail-out checker. */
    template <class BailOutCheckerType, LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3), LL_TEMPLATE(4), LL_TEMPLATE(5)>
    void callChecked (const BailOutCheckerType& bailOutChecker,
                      void (ListenerClass::*callbackFunction) (P1, P2, P3, P4, P5),
                      LL_PARAM(1), LL_PARAM(2), LL_PARAM(3), LL_PARAM(4), LL_PARAM(5))
    {
        for (Iterator<BailOutCheckerType, ThisType> iter (*this); iter.next (bailOutChecker);)
            (iter.getListener()->*callbackFunction) (param1, param2, param3, param4, param5);
    }

    //==============================================================================
    template <class BailOutCheckerType, LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3), LL_TEMPLATE(4), LL_TEMPLATE(5)>
    class CallbackMessage5 : public juce::MessageManager::MessageBase
    {
    public:
        CallbackMessage5 (const ThisType* all,
                          const BailOutCheckerType& bailOutChecker,
                          void (ListenerClass::*callbackFunction) (P1, P2, P3, P4, P5),
                          LL_PARAM(1), LL_PARAM(2), LL_PARAM(3), LL_PARAM(4), LL_PARAM(5)) noexcept
            : listenerList (const_cast<ThisType*> (all)),
            bailOutChecker (bailOutChecker),
            callback (callbackFunction),
            param1 (param1),
            param2 (param2),
            param3 (param3),
            param4 (param4),
            param5 (param5)
        {}

        void messageCallback() override
        {
            if (const ThisType* const all = listenerList)
                listenerList->callChecked(bailOutChecker, callback, param1, param2, param3, param4, param5);
        }

    private:
        juce::WeakReference<ThisType> listenerList;
        const BailOutCheckerType& bailOutChecker;
        void (ListenerClass::*callback) (P1, P2, P3, P4, P5);
        LL_PARAM(1);
        LL_PARAM(2);
        LL_PARAM(3);
        LL_PARAM(4);
        LL_PARAM(5);

        JUCE_DECLARE_NON_COPYABLE (CallbackMessage5)
    };

    template <LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3), LL_TEMPLATE(4), LL_TEMPLATE(5)>
    void callAsync (void (ListenerClass::*callbackFunction) (P1, P2, P3, P4, P5), LL_PARAM(1), LL_PARAM(2), LL_PARAM(3), LL_PARAM(4), LL_PARAM(5))
    {
        (new CallbackMessage5<DummyBailOutChecker, P1, P2, P3, P4, P5>
            (this, static_cast <const DummyBailOutChecker&> (DummyBailOutChecker()), callbackFunction, param1, param2, param3, param4, param5))->post();
    }

    template <class BailOutCheckerType, LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3), LL_TEMPLATE(4), LL_TEMPLATE(5)>
    void callAsyncChecked (const BailOutCheckerType& bailOutChecker,
                           void (ListenerClass::*callbackFunction) (P1, P2, P3, P4, P5),
                           LL_PARAM(1), LL_PARAM(2), LL_PARAM(3), LL_PARAM(4), LL_PARAM(5))
    {
        (new CallbackMessage5<BailOutCheckerType, P1, P2, P3, P4, P5>
            (this, bailOutChecker, callbackFunction, param1, param2, param3, param4, param5))->post();
    }

    //==============================================================================
    /** Calls a member function on each listener in the list, with 5 parameters. */
    template <LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3), LL_TEMPLATE(4), LL_TEMPLATE(5), LL_TEMPLATE(6)>
    void call (void (ListenerClass::*callbackFunction) (P1, P2, P3, P4, P5, P6),
               LL_PARAM(1), LL_PARAM(2), LL_PARAM(3), LL_PARAM(4), LL_PARAM(5), LL_PARAM(6))
    {
        for (Iterator<DummyBailOutChecker, ThisType> iter (*this); iter.next();)
            (iter.getListener()->*callbackFunction) (param1, param2, param3, param4, param5, param6);
    }

    /** Calls a member function on each listener in the list, with 5 parameters and a bail-out-checker.
        See the class description for info about writing a bail-out checker. */
    template <class BailOutCheckerType, LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3), LL_TEMPLATE(4), LL_TEMPLATE(5), LL_TEMPLATE(6)>
    void callChecked (const BailOutCheckerType& bailOutChecker,
                      void (ListenerClass::*callbackFunction) (P1, P2, P3, P4, P5, P6),
                      LL_PARAM(1), LL_PARAM(2), LL_PARAM(3), LL_PARAM(4), LL_PARAM(5), LL_PARAM(6))
    {
        for (Iterator<BailOutCheckerType, ThisType> iter (*this); iter.next (bailOutChecker);)
            (iter.getListener()->*callbackFunction) (param1, param2, param3, param4, param5, param6);
    }

    //==============================================================================
    template <class BailOutCheckerType, LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3), LL_TEMPLATE(4), LL_TEMPLATE(5), LL_TEMPLATE(6)>
    class CallbackMessage6 : public juce::MessageManager::MessageBase
    {
    public:
        CallbackMessage6 (const ThisType* all,
                          const BailOutCheckerType& bailOutChecker,
                          void (ListenerClass::*callbackFunction) (P1, P2, P3, P4, P5, P6),
                          LL_PARAM(1), LL_PARAM(2), LL_PARAM(3), LL_PARAM(4), LL_PARAM(5), LL_PARAM(6)) noexcept
            : listenerList (const_cast<ThisType*> (all)),
            bailOutChecker (bailOutChecker),
            callback (callbackFunction),
            param1 (param1),
            param2 (param2),
            param3 (param3),
            param4 (param4),
            param5 (param5),
            param6 (param6)
        {}

        void messageCallback() override
        {
            if (const ThisType* const all = listenerList)
                listenerList->callChecked(bailOutChecker, callback, param1, param2, param3, param4, param5, param6);
        }

    private:
        juce::WeakReference<ThisType> listenerList;
        const BailOutCheckerType& bailOutChecker;
        void (ListenerClass::*callback) (P1, P2, P3, P4, P5, P6);
        LL_PARAM(1);
        LL_PARAM(2);
        LL_PARAM(3);
        LL_PARAM(4);
        LL_PARAM(5);
        LL_PARAM(6);

        JUCE_DECLARE_NON_COPYABLE (CallbackMessage6)
    };

    template <LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3), LL_TEMPLATE(4), LL_TEMPLATE(5), LL_TEMPLATE(6)>
    void callAsync (void (ListenerClass::*callbackFunction) (P1, P2, P3, P4, P5, P6), LL_PARAM(1), LL_PARAM(2), LL_PARAM(3), LL_PARAM(4), LL_PARAM(5), LL_PARAM(6))
    {
        (new CallbackMessage6<DummyBailOutChecker, P1, P2, P3, P4, P5, P6>
            (this, static_cast <const DummyBailOutChecker&> (DummyBailOutChecker()), callbackFunction, param1, param2, param3, param4, param5, param6))->post();
    }

    template <class BailOutCheckerType, LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3), LL_TEMPLATE(4), LL_TEMPLATE(5), LL_TEMPLATE(6)>
    void callAsyncChecked (const BailOutCheckerType& bailOutChecker,
                           void (ListenerClass::*callbackFunction) (P1, P2, P3, P4, P5, P6),
                           LL_PARAM(1), LL_PARAM(2), LL_PARAM(3), LL_PARAM(4), LL_PARAM(5), LL_PARAM(6))
    {
        (new CallbackMessage6<BailOutCheckerType, P1, P2, P3, P4, P5, P6>
            (this, bailOutChecker, callbackFunction, param1, param2, param3, param4, param5, param6))->post();
    }

    //==============================================================================
    /** A dummy bail-out checker that always returns false.
        See the ListenerList notes for more info about bail-out checkers.
    */
    class DummyBailOutChecker
    {
    public:
        inline bool shouldBailOut() const noexcept     { return false; }
    };

    //==============================================================================
    /** Iterates the listeners in a ListenerList. */
    template <class BailOutCheckerType, class ListType>
    class Iterator
    {
    public:
        //==============================================================================
        Iterator (const ListType& listToIterate) noexcept
            : list (listToIterate), index (listToIterate.size())
        {}

        ~Iterator() noexcept {}

        //==============================================================================
        bool next() noexcept
        {
            if (index <= 0)
                return false;

            const int listSize = list.size();

            if (--index < listSize)
                return true;

            index = listSize - 1;
            return index >= 0;
        }

        bool next (const BailOutCheckerType& bailOutChecker) noexcept
        {
            return (! bailOutChecker.shouldBailOut()) && next();
        }

        typename ListType::ListenerType* getListener() const noexcept
        {
            return list.getListeners().getUnchecked (index);
        }

        //==============================================================================
    private:
        const ListType& list;
        int index;

        JUCE_DECLARE_NON_COPYABLE (Iterator)
    };

    const ArrayType& getListeners() const noexcept          { return listeners; }

private:
    //==============================================================================
    typename juce::WeakReference<ThisType>::Master masterReference;
    friend class juce::WeakReference<ThisType>;

    ArrayType listeners;
    juce::CriticalSection listenerLock;

    JUCE_DECLARE_NON_COPYABLE (AsyncListenerList)

    #undef LL_TEMPLATE
    #undef LL_PARAM
};

AudioProcessorValueTreeState && thread-safety
#2

was this implemented into the ListenerList class?


#3

nops. c++17 will come before this will get in :smiley:


#4

That’s exactly what I am looking for at the moment: ListenerList::callAsync !
Is there any chance that this will be added to the ListenerList?

I have a thread that reads and synchronises FFmpeg streams, which provides a VideoListener to receive the frames and to send a presentationTimestampChanged. When I use that callback to set a slider, it triggers a repaint, which throws an assert, because it’s not the message thread.

Thanks so much!


#5

+1 on this. It just makes sense, considering how often listeners are used in JUCE for UI related work on and off the message thread.


#6

yes, but i would actually rewrite this macro mess with variadic templates. type safety and (mostly) unlimited numbers of callback arguments with lesser and cleaner lines of code. you need to ask the companies still trying to target old dino-users if we are allowed to do that


#7

probably now with c+11 as minimum for juce this can be done. will see what i can come up with