1 /* 2 * Copyright (c) 2021, The OpenThread Authors. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. Neither the name of the copyright holder nor the 13 * names of its contributors may be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #ifndef OTBR_COMMON_CALLBACK_HPP_ 30 #define OTBR_COMMON_CALLBACK_HPP_ 31 32 #include "openthread-br/config.h" 33 34 #include <functional> 35 #include <type_traits> 36 37 namespace otbr { 38 39 template <class T> class OnceCallback; 40 41 /** 42 * A callback which can be invoked at most once. 43 * 44 * IsNull is guaranteed to return true once the callback has been invoked. 45 * 46 * Example usage: 47 * OnceCallback<int(int)> square([](int x) { return x * x; }); 48 * std::move(square)(5); // Returns 25. 49 * std::move(square)(6); // Crashes since `square` has already run. 50 * square(7); // Compiling error. 51 * 52 * Inspired by Chromium base::OnceCallback 53 * (https://chromium.googlesource.com/chromium/src.git/+/refs/heads/main/base/callback.h). 54 */ 55 template <typename R, typename... Args> class OnceCallback<R(Args...)> 56 { 57 public: 58 // Constructs a new `OnceCallback` instance with a callable. 59 // 60 // This constructor is for matching std::function<> and lambda and the 61 // `std::enable_if_t` check is only required for working around gcc 4.x 62 // compiling issue which trying to instantiate this template constructor 63 // for use cases like `::mOnceCallback(aOnceCallback)`. 64 template <typename T, typename = typename std::enable_if<!std::is_same<OnceCallback, T>::value>::type> OnceCallback(T && aFunc)65 OnceCallback(T &&aFunc) 66 : mFunc(std::forward<T>(aFunc)) 67 { 68 } 69 OnceCallback(OnceCallback && aCallback)70 OnceCallback(OnceCallback &&aCallback) 71 : mFunc(std::move(aCallback.mFunc)) 72 { 73 aCallback.mFunc = nullptr; 74 } 75 operator =(OnceCallback && aCallback)76 OnceCallback &operator=(OnceCallback &&aCallback) 77 { 78 mFunc = std::move(aCallback.mFunc); 79 aCallback.mFunc = nullptr; 80 81 return *this; 82 } 83 84 OnceCallback(const OnceCallback &) = delete; 85 OnceCallback &operator=(const OnceCallback &) = delete; 86 operator ()(Args...) const87 R operator()(Args...) const & 88 { 89 static_assert(!sizeof(*this), "OnceCallback::() can only be invoked on a non-const " 90 "rvalue, i.e. std::move(callback)()."); 91 } 92 operator ()(Args...aArgs)93 R operator()(Args... aArgs) && 94 { 95 // Move `this` to a local variable to clear internal state 96 // before invoking the callback function. 97 OnceCallback cb = std::move(*this); 98 99 return cb.mFunc(std::forward<Args>(aArgs)...); 100 } 101 IsNull() const102 bool IsNull() const { return mFunc == nullptr; } 103 104 private: 105 std::function<R(Args...)> mFunc; 106 }; 107 108 } // namespace otbr 109 110 #endif // OTBR_COMMON_CALLBACK_HPP_ 111