xref: /aosp_15_r20/external/pigweed/pw_sync/public/pw_sync/inline_borrowable.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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