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 <functional> 33 #include <type_traits> 34 35 namespace otbr { 36 37 template <class T> class OnceCallback; 38 39 /** 40 * A callback which can be invoked at most once. 41 * 42 * IsNull is guaranteed to return true once the callback has been invoked. 43 * 44 * Example usage: 45 * OnceCallback<int(int)> square([](int x) { return x * x; }); 46 * std::move(square)(5); // Returns 25. 47 * std::move(square)(6); // Crashes since `square` has already run. 48 * square(7); // Compiling error. 49 * 50 * Inspired by Chromium base::OnceCallback 51 * (https://chromium.googlesource.com/chromium/src.git/+/refs/heads/main/base/callback.h). 52 * 53 */ 54 template <typename R, typename... Args> class OnceCallback<R(Args...)> 55 { 56 public: 57 // Constructs a new `OnceCallback` instance with a callable. 58 // 59 // This constructor is for matching std::function<> and lambda and the 60 // `std::enable_if_t` check is only required for working around gcc 4.x 61 // compiling issue which trying to instantiate this template constructor 62 // for use cases like `::mOnceCallback(aOnceCallback)`. 63 template <typename T, typename = typename std::enable_if<!std::is_same<OnceCallback, T>::value>::type> OnceCallback(T && func)64 OnceCallback(T &&func) 65 : mFunc(std::forward<T>(func)) 66 { 67 } 68 69 OnceCallback(const OnceCallback &) = delete; 70 OnceCallback &operator=(const OnceCallback &) = delete; 71 OnceCallback(OnceCallback &&) = default; 72 OnceCallback &operator=(OnceCallback &&) = default; 73 operator ()(Args...) const74 R operator()(Args...) const & 75 { 76 static_assert(!sizeof(*this), "OnceCallback::() can only be invoked on a non-const " 77 "rvalue, i.e. std::move(callback)()."); 78 } 79 operator ()(Args...args)80 R operator()(Args... args) && 81 { 82 // Move `this` to a local variable to clear internal state 83 // before invoking the callback function. 84 OnceCallback cb = std::move(*this); 85 86 return cb.mFunc(std::forward<Args>(args)...); 87 } 88 IsNull() const89 bool IsNull() const { return mFunc == nullptr; } 90 91 private: 92 std::function<R(Args...)> mFunc; 93 }; 94 95 } // namespace otbr 96 97 #endif // OTBR_COMMON_CALLBACK_HPP_ 98