| @@ -114,6 +114,18 @@ public: | |||||
| }); | }); | ||||
| } | } | ||||
| /** Adds a listener that will be automatically removed again when the Guard is destroyed. | |||||
| Be very careful to ensure that the ErasedScopeGuard is destroyed or released before the | |||||
| ListenerList is destroyed, otherwise the ErasedScopeGuard may attempt to dereference a | |||||
| dangling pointer when it is destroyed, which will result in a crash. | |||||
| */ | |||||
| ErasedScopeGuard addScoped (ListenerClass& listenerToAdd) | |||||
| { | |||||
| add (&listenerToAdd); | |||||
| return ErasedScopeGuard { [this, &listenerToAdd] { remove (&listenerToAdd); } }; | |||||
| } | |||||
| /** Returns the number of registered listeners. */ | /** Returns the number of registered listeners. */ | ||||
| int size() const noexcept { return listeners.size(); } | int size() const noexcept { return listeners.size(); } | ||||
| @@ -146,6 +146,7 @@ | |||||
| #include "misc/juce_Result.cpp" | #include "misc/juce_Result.cpp" | ||||
| #include "misc/juce_Uuid.cpp" | #include "misc/juce_Uuid.cpp" | ||||
| #include "misc/juce_ConsoleApplication.cpp" | #include "misc/juce_ConsoleApplication.cpp" | ||||
| #include "misc/juce_ScopeGuard.cpp" | |||||
| #include "network/juce_MACAddress.cpp" | #include "network/juce_MACAddress.cpp" | ||||
| #include "network/juce_NamedPipe.cpp" | #include "network/juce_NamedPipe.cpp" | ||||
| #include "network/juce_Socket.cpp" | #include "network/juce_Socket.cpp" | ||||
| @@ -259,6 +259,7 @@ JUCE_END_IGNORE_WARNINGS_MSVC | |||||
| #include "containers/juce_ArrayBase.h" | #include "containers/juce_ArrayBase.h" | ||||
| #include "containers/juce_Array.h" | #include "containers/juce_Array.h" | ||||
| #include "containers/juce_LinkedListPointer.h" | #include "containers/juce_LinkedListPointer.h" | ||||
| #include "misc/juce_ScopeGuard.h" | |||||
| #include "containers/juce_ListenerList.h" | #include "containers/juce_ListenerList.h" | ||||
| #include "containers/juce_OwnedArray.h" | #include "containers/juce_OwnedArray.h" | ||||
| #include "containers/juce_ReferenceCountedArray.h" | #include "containers/juce_ReferenceCountedArray.h" | ||||
| @@ -86,35 +86,6 @@ template <typename Object, typename OtherObject, typename Member, typename Other | |||||
| return copy; | return copy; | ||||
| } | } | ||||
| /** An easy way to ensure that a function is called at the end of the current | |||||
| scope. | |||||
| Usage: | |||||
| @code | |||||
| { | |||||
| if (flag == true) | |||||
| return; | |||||
| // While this code executes, flag is true e.g. to prevent reentrancy | |||||
| flag = true; | |||||
| // When we exit this scope, flag must be false | |||||
| const ScopeGuard scope { [&] { flag = false; } }; | |||||
| if (checkInitialCondition()) | |||||
| return; // Scope's lambda will fire here... | |||||
| if (checkCriticalCondition()) | |||||
| throw std::runtime_error{}; // ...or here... | |||||
| doWorkHavingEstablishedPreconditions(); | |||||
| } // ...or here! | |||||
| @endcode | |||||
| @tags{Core} | |||||
| */ | |||||
| template <typename Fn> struct ScopeGuard : Fn { ~ScopeGuard() { Fn::operator()(); } }; | |||||
| template <typename Fn> ScopeGuard (Fn) -> ScopeGuard<Fn>; | |||||
| #ifndef DOXYGEN | #ifndef DOXYGEN | ||||
| namespace detail | namespace detail | ||||
| { | { | ||||
| @@ -0,0 +1,55 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library. | |||||
| Copyright (c) 2022 - Raw Material Software Limited | |||||
| JUCE is an open source library subject to commercial or open-source | |||||
| licensing. | |||||
| The code included in this file is provided under the terms of the ISC license | |||||
| http://www.isc.org/downloads/software-support-policy/isc-license. Permission | |||||
| To use, copy, modify, and/or distribute this software for any purpose with or | |||||
| without fee is hereby granted provided that the above copyright notice and | |||||
| this permission notice appear in all copies. | |||||
| JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||||
| EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||||
| DISCLAIMED. | |||||
| ============================================================================== | |||||
| */ | |||||
| namespace juce | |||||
| { | |||||
| ErasedScopeGuard::ErasedScopeGuard (std::function<void()> d) | |||||
| : detach (std::move (d)) {} | |||||
| ErasedScopeGuard::ErasedScopeGuard (ErasedScopeGuard&& other) noexcept | |||||
| : detach (std::exchange (other.detach, nullptr)) {} | |||||
| ErasedScopeGuard& ErasedScopeGuard::operator= (ErasedScopeGuard&& other) noexcept | |||||
| { | |||||
| ErasedScopeGuard token { std::move (other) }; | |||||
| std::swap (token.detach, detach); | |||||
| return *this; | |||||
| } | |||||
| ErasedScopeGuard::~ErasedScopeGuard() noexcept | |||||
| { | |||||
| reset(); | |||||
| } | |||||
| void ErasedScopeGuard::reset() | |||||
| { | |||||
| if (auto d = std::exchange (detach, nullptr)) | |||||
| d(); | |||||
| } | |||||
| void ErasedScopeGuard::release() | |||||
| { | |||||
| detach = nullptr; | |||||
| } | |||||
| } // namespace juce | |||||
| @@ -0,0 +1,113 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library. | |||||
| Copyright (c) 2022 - Raw Material Software Limited | |||||
| JUCE is an open source library subject to commercial or open-source | |||||
| licensing. | |||||
| The code included in this file is provided under the terms of the ISC license | |||||
| http://www.isc.org/downloads/software-support-policy/isc-license. Permission | |||||
| To use, copy, modify, and/or distribute this software for any purpose with or | |||||
| without fee is hereby granted provided that the above copyright notice and | |||||
| this permission notice appear in all copies. | |||||
| JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||||
| EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||||
| DISCLAIMED. | |||||
| ============================================================================== | |||||
| */ | |||||
| namespace juce | |||||
| { | |||||
| /** An easy way to ensure that a function is called at the end of the current | |||||
| scope. | |||||
| Usage: | |||||
| @code | |||||
| { | |||||
| if (flag == true) | |||||
| return; | |||||
| // While this code executes, flag is true e.g. to prevent reentrancy | |||||
| flag = true; | |||||
| // When we exit this scope, flag must be false | |||||
| const ScopeGuard scope { [&] { flag = false; } }; | |||||
| if (checkInitialCondition()) | |||||
| return; // Scope's lambda will fire here... | |||||
| if (checkCriticalCondition()) | |||||
| throw std::runtime_error{}; // ...or here... | |||||
| doWorkHavingEstablishedPreconditions(); | |||||
| } // ...or here! | |||||
| @endcode | |||||
| @tags{Core} | |||||
| */ | |||||
| template <typename Fn> struct ScopeGuard : Fn { ~ScopeGuard() { Fn::operator()(); } }; | |||||
| template <typename Fn> ScopeGuard (Fn) -> ScopeGuard<Fn>; | |||||
| /** | |||||
| A ScopeGuard that uses a std::function internally to allow type erasure. | |||||
| This can be handy; it allows lots of ErasedScopeGuards, all with different | |||||
| callbacks, to be stored in a homogeneous container. | |||||
| An instance of this type will automatically call its callback when it is destroyed. | |||||
| ErasedScopeGuard has a few similarities with std::unique_ptr: | |||||
| - Calling reset() on a unique_ptr destroys the object if it hasn't been destroyed yet | |||||
| and puts the unique_ptr back into a default/null state; calling reset() on an | |||||
| ErasedScopeGuard calls the callback if it hasn't been called yet and puts the Guard | |||||
| back into a default/null state. | |||||
| - Calling release() on a unique_ptr returns the unique_ptr back to a default state | |||||
| without destroying the managed object; calling release() on an ErasedScopeGuard | |||||
| returns the Guard back to a default state without calling the callback. | |||||
| - Moving a unique_ptr transfers the responsibility of destroying the managed object | |||||
| to another unique_ptr instance; moving an ErasedScopeGuard transfers the | |||||
| responsibility of calling the callback to another Guard instance. | |||||
| */ | |||||
| class [[nodiscard]] ErasedScopeGuard | |||||
| { | |||||
| public: | |||||
| /** Constructs an ErasedScopeGuard with no callback. */ | |||||
| ErasedScopeGuard() = default; | |||||
| /** Constructs an ErasedScopeGuard that will call the provided callback | |||||
| when the Guard is destroyed. | |||||
| */ | |||||
| explicit ErasedScopeGuard (std::function<void()> d); | |||||
| /** Constructs an instance that assumes responsibility for calling other's callback. */ | |||||
| ErasedScopeGuard (ErasedScopeGuard&& other) noexcept; | |||||
| /** Calls the stored callback, if any, then assumes responsibility for calling | |||||
| other's callback. After this call, other will be reset to its default state. | |||||
| */ | |||||
| ErasedScopeGuard& operator= (ErasedScopeGuard&& other) noexcept; | |||||
| /** Destructor, calls the callback assigned to this ScopeGuard. | |||||
| */ | |||||
| ~ErasedScopeGuard() noexcept; | |||||
| /** Calls the stored callback, if any, then resets this instance to its | |||||
| default state. | |||||
| */ | |||||
| void reset(); | |||||
| /** Resets this instance to its default state without calling the stored | |||||
| callback. | |||||
| */ | |||||
| void release(); | |||||
| JUCE_DECLARE_NON_COPYABLE (ErasedScopeGuard) | |||||
| private: | |||||
| std::function<void()> detach; | |||||
| }; | |||||
| } // namespace juce | |||||