1 // Copyright 2022 The Pigweed Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 // use this file except in compliance with the License. You may obtain a copy of 5 // the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations under 13 // the License. 14 #pragma once 15 16 #include <tuple> 17 #include <utility> 18 19 #include "pw_sync/borrow.h" 20 #include "pw_sync/internal/borrowable_storage.h" 21 #include "pw_sync/mutex.h" 22 #include "pw_sync/virtual_basic_lockable.h" 23 24 namespace pw::sync { 25 26 /// `InlineBorrowable` holds an object of `GuardedType` and a Lock that guards 27 /// access to the object. It should be used when an object should be guarded for 28 /// its entire lifecycle by a single lock. 29 /// 30 /// This object should be shared with other componetns as a reference of type 31 /// `Borrowable<GuardedType, LockInterface>`. 32 /// 33 template <typename GuardedType, 34 typename Lock = pw::sync::VirtualMutex, 35 typename LockInterface = pw::sync::VirtualBasicLockable> 36 class InlineBorrowable : private internal::BorrowableStorage<GuardedType, Lock>, 37 public Borrowable<GuardedType, LockInterface> { 38 using Storage = internal::BorrowableStorage<GuardedType, Lock>; 39 using Base = Borrowable<GuardedType, LockInterface>; 40 41 public: 42 /// Construct the guarded object and lock using their default constructors. InlineBorrowable()43 constexpr InlineBorrowable() 44 : Storage(std::in_place), Base(Storage::object_, Storage::lock_) {} 45 46 /// Construct the guarded object by providing its constructor arguments 47 /// inline. The lock is constructed using its default constructor. 48 /// 49 /// This constructor supports list initialization for arrays, structs, and 50 /// other objects such as `std::array`. 51 /// 52 /// Example: 53 /// 54 /// @code 55 /// InlineBorrowable<Foo> foo(std::in_place, foo_arg1, foo_arg2); 56 /// 57 /// InlineBorrowable<std::array<int, 2>> foo_array(std::in_place, 1, 2); 58 /// @endcode 59 /// 60 template <typename... Args> InlineBorrowable(std::in_place_t,Args &&...args)61 constexpr explicit InlineBorrowable(std::in_place_t, Args&&... args) 62 : Storage(std::in_place, std::forward<Args>(args)...), 63 Base(Storage::object_, Storage::lock_) {} 64 65 /// Construct the guarded object and lock by providing their construction 66 /// parameters using separate tuples. The 2nd tuple can be ommitted to 67 /// construct the lock using its default constructor. 68 /// 69 /// Example: 70 /// 71 /// @code 72 /// InlineBorrowable<Foo> foo(std::forward_as_tuple(foo_arg1, foo_arg2)); 73 /// 74 /// InlineBorrowable<Foo, MyLock> foo_lock( 75 /// std::forward_as_tuple(foo_arg1, foo_arg2), 76 /// std::forward_as_tuple(lock_arg1, lock_arg2)); 77 /// @endcode 78 /// 79 /// @note This constructor only supports list initialization with C++20 or 80 /// later, because it requires https://wg21.link/p0960. 81 /// 82 template <typename... ObjectArgs, typename... LockArgs> 83 constexpr explicit InlineBorrowable( 84 std::tuple<ObjectArgs...>&& object_args, 85 std::tuple<LockArgs...>&& lock_args = std::make_tuple()) Storage(std::forward<std::tuple<ObjectArgs...>> (object_args),std::forward<std::tuple<LockArgs...>> (lock_args))86 : Storage(std::forward<std::tuple<ObjectArgs...>>(object_args), 87 std::forward<std::tuple<LockArgs...>>(lock_args)), 88 Base(Storage::object_, Storage::lock_) {} 89 90 /// Construct the guarded object and lock by providing factory functions. The 91 /// 2nd callable can be ommitted to construct the lock using its default 92 /// constructor. 93 /// 94 /// Example: 95 /// 96 /// @code 97 /// InlineBorrowable<Foo> foo([&]{ return Foo{foo_arg1, foo_arg2}; }); 98 /// 99 /// InlineBorrowable<Foo, MyLock> foo_lock( 100 /// [&]{ return Foo{foo_arg1, foo_arg2}; } 101 /// [&]{ return MyLock{lock_arg1, lock_arg2}; } 102 /// @endcode 103 /// 104 template <typename ObjectConstructor, 105 typename LockConstructor = Lock(), 106 typename = std::enable_if_t< 107 std::is_invocable_r_v<GuardedType&&, ObjectConstructor>>, 108 typename = std::enable_if_t< 109 std::is_invocable_r_v<Lock&&, LockConstructor>>> 110 constexpr explicit InlineBorrowable( 111 const ObjectConstructor& object_ctor, 112 const LockConstructor& lock_ctor = internal::DefaultConstruct<Lock>) Storage(object_ctor,lock_ctor)113 : Storage(object_ctor, lock_ctor), 114 Base(Storage::object_, Storage::lock_) {} 115 116 template <typename ObjectConstructor, 117 typename LockConstructor = Lock(), 118 typename = std::enable_if_t< 119 std::is_invocable_r_v<GuardedType&&, ObjectConstructor>>, 120 typename = std::enable_if_t< 121 std::is_invocable_r_v<Lock&&, LockConstructor>>> 122 constexpr explicit InlineBorrowable( 123 ObjectConstructor& object_ctor, 124 const LockConstructor& lock_ctor = internal::DefaultConstruct<Lock>) Storage(object_ctor,lock_ctor)125 : Storage(object_ctor, lock_ctor), 126 Base(Storage::object_, Storage::lock_) {} 127 128 template <typename ObjectConstructor, 129 typename LockConstructor = Lock(), 130 typename = std::enable_if_t< 131 std::is_invocable_r_v<GuardedType&&, ObjectConstructor>>, 132 typename = std::enable_if_t< 133 std::is_invocable_r_v<Lock&&, LockConstructor>>> InlineBorrowable(const ObjectConstructor & object_ctor,LockConstructor & lock_ctor)134 constexpr explicit InlineBorrowable(const ObjectConstructor& object_ctor, 135 LockConstructor& lock_ctor) 136 : Storage(object_ctor, lock_ctor), 137 Base(Storage::object_, Storage::lock_) {} 138 139 template <typename ObjectConstructor, 140 typename LockConstructor = Lock(), 141 typename = std::enable_if_t< 142 std::is_invocable_r_v<GuardedType&&, ObjectConstructor>>, 143 typename = std::enable_if_t< 144 std::is_invocable_r_v<Lock&&, LockConstructor>>> InlineBorrowable(ObjectConstructor & object_ctor,LockConstructor & lock_ctor)145 constexpr explicit InlineBorrowable(ObjectConstructor& object_ctor, 146 LockConstructor& lock_ctor) 147 : Storage(object_ctor, lock_ctor), 148 Base(Storage::object_, Storage::lock_) {} 149 }; 150 151 } // namespace pw::sync 152