1 // Copyright (C) 2017 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://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,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #pragma once
16
17 #include "aemu/base/Compiler.h"
18 #include "aemu/base/TypeTraits.h"
19 #include "aemu/base/memory/LazyInstance.h"
20
21 #include <functional>
22 #include <tuple>
23 #include <type_traits>
24 #include <utility>
25
26 //
27 // OnDemand<T> - a wrapper class for on-demand initialization of variables.
28 //
29 // Sometimes a function or a class contains some variables that are only used
30 // if some condition is met, e.g.:
31 //
32 // void boo(bool print) {
33 // Printer printer;
34 // ...
35 // if (print) printer.out("data");
36 // }
37 //
38 // It's usually OK to have code like this, but if |printer| initialization is
39 // slow, every call with |print| == false would waste quite noticeable amount of
40 // time for nothing while creating |printer| to never use it.
41 //
42 // OnDemand<T> solves the problem - its initialization only captures the
43 // parameters needed to construct T, but T itself is only constructed on the
44 // first use:
45 //
46 // void boo(bool print) {
47 // auto printer = makeOnDemand<Printer>();
48 // ...
49 // if (print) printer->out("data");
50 // }
51 //
52 // This new version of code would only call Printer's ctor if |print| is true
53 // and we needed to call some |printer|'s method.
54 //
55 // This is especially useful for class members, where one sometimes there's
56 // a part like that, but tracking its initialized state across multiple member
57 // functions is hard and error-prone. OnDemand<T> hides it from the user.
58 //
59 // Usage:
60 //
61 // // Initialize |i| to 10 on first use:
62 // auto i = makeOnDemand<int>(10);
63 // // Initialize |i| to 1000th prime on first use:
64 // auto i = makeOnDemand<int>([]{ return std::make_tuple(calc1000thPrime(); });
65 // // Or simpler:
66 // auto i = makeOnDemand<int>([]{ return calc10000thPrime(); });
67 // });
68 // // Perform some operation only if the on demand object has already been
69 // // created.
70 // i.ifExists([](int& val) { val += 10; });
71 //
72 // // Create a complex object with tons of parameters:
73 // auto obj = makeOnDemand<QWindow>([app, text] {
74 // return std::make_tuple(app, translate(text));
75 // });
76 // // Explicitly destroy the object:
77 // obj.clear();
78 //
79 // // Add an on-demand class member:
80 // class C {
81 // MemberOnDemand<QWindow, QApplication, string> mWindow;
82 // C() : mWindow([app, text] { return std::make_tuple(...); }) {}
83 // };
84 //
85
86 namespace android {
87 namespace base {
88
89 namespace internal {
90
91 //
92 // A bit of template magic to unpack arguments from a tuple and call a function
93 // using those arguments:
94 // std::tuple<int, char, char*> -> func(tuple<0>, tuple<1>, tuple<2>)
95 //
96 // To call a function with arguments from a tuple one needs to use syntax:
97 // template <class ... Args>
98 // void call(std::tuple<Args> args) {
99 // call_impl(args, MakeSeqT<sizeof...(Args)>());
100 // }
101 // template <class ... Args, int ... N>
102 // void call_impl(std::tuple<Args> args, Seq<N...>) {
103 // func(std::get<N>(args)...); // expands std::get<>() for each N
104 // }
105 //
106 // TODO: C++14 gives us std::index_sequence<> in STL, so we'll be able to get
107 // rid of out custom Seq<> class.
108 // C++17 got std::apply() call to replace all of this altogether.
109 //
110
111 // If user wants to create an OnDemand<> wrapper with already calculated
112 // parameters, this class would hold those and convert them into a tuple
113 // to call constructor.
114 template <class... Args>
115 struct TupleHolder {
116 std::tuple<Args...> args;
operatorTupleHolder117 std::tuple<Args...>&& operator()() { return std::move(args); }
118 };
119
120 // A convenience class for the user to be able to return a single constructor
121 // argument without wrapping it into a tuple.
122 template <class Callable>
123 struct TupleCreator {
124 mutable Callable mCallable;
125 using ReturnT = decltype(std::declval<Callable>()());
126
TupleCreatorTupleCreator127 TupleCreator(Callable&& c) : mCallable(std::move(c)) {}
128
operatorTupleCreator129 std::tuple<ReturnT> operator()() const {
130 return std::make_tuple(mCallable());
131 }
132 };
133
134 struct OnDemandState {
inNoObjectStateOnDemandState135 bool inNoObjectState() const { return !mConstructed; }
needConstructionOnDemandState136 bool needConstruction() { return !mConstructed; }
doneConstructingOnDemandState137 void doneConstructing() { mConstructed = true; }
138
needDestructionOnDemandState139 bool needDestruction() { return mConstructed; }
doneDestroyingOnDemandState140 void doneDestroying() { mConstructed = false; }
141
142 bool mConstructed = false;
143 };
144
145 } // namespace internal
146
147 template <class T, class CtorArgsGetter, class State = internal::OnDemandState>
148 class OnDemand {
149 DISALLOW_COPY_AND_ASSIGN(OnDemand);
150
151 public:
OnDemand(CtorArgsGetter && argsGetter)152 OnDemand(CtorArgsGetter&& argsGetter)
153 : mCtorArgsGetter(std::move(argsGetter)) {}
154
OnDemand(OnDemand && other)155 OnDemand(OnDemand&& other)
156 : mCtorArgsGetter(std::move(other.mCtorArgsGetter)) {
157 if (other.hasInstance()) {
158 new (&mStorage) T(std::move(*other.asT()));
159 mState.doneConstructing();
160 other.clear();
161 }
162 }
163
164 template <class CompatibleArgsGetter,
165 class = enable_if_c<!is_template_instantiation_of<
166 decltype(std::declval<CompatibleArgsGetter>()()),
167 std::tuple>::value>>
OnDemand(CompatibleArgsGetter && argsGetter)168 OnDemand(CompatibleArgsGetter&& argsGetter)
169 : OnDemand(CtorArgsGetter([argsGetter = std::move(argsGetter)] {
170 return std::make_tuple(argsGetter());
171 })) {}
172
173 template <class Arg0,
174 class = enable_if_c<!is_callable_with_args<Arg0, void()>::value>>
175 OnDemand(Arg0&& arg0, void* = nullptr)
176 : OnDemand(CtorArgsGetter([arg0 = std::forward<Arg0>(arg0)] {
177 return std::make_tuple(arg0);
178 })) {}
179
180 template <class Arg0, class Arg1, class... Args>
OnDemand(Arg0 && arg0,Arg1 && arg1,Args &&...args)181 OnDemand(Arg0&& arg0, Arg1&& arg1, Args&&... args)
182 : OnDemand(CtorArgsGetter(
183 [res = std::make_tuple(std::forward<Arg0>(arg0),
184 std::forward<Arg1>(arg1),
185 std::forward<Args>(args)...)] {
186 return res;
187 })) {}
188
~OnDemand()189 ~OnDemand() { clear(); }
190
hasInstance()191 bool hasInstance() const { return !mState.inNoObjectState(); }
192
get()193 const T& get() const { return *ptr(); }
get()194 T& get() { return *ptr(); }
195
196 const T* operator->() const { return ptr(); }
197 T* operator->() { return ptr(); }
198
199 const T& operator*() const { return get(); }
200 T& operator*() { return get(); }
201
ptr()202 T* ptr() {
203 return const_cast<T*>(const_cast<const OnDemand*>(this)->ptr());
204 }
205
ptr()206 const T* ptr() const {
207 if (mState.needConstruction()) {
208 construct();
209 mState.doneConstructing();
210 }
211 return asT();
212 }
213
clear()214 void clear() {
215 if (mState.needDestruction()) {
216 asT()->~T();
217 mState.doneDestroying();
218 }
219 }
220
221 template <class Func, class = enable_if<is_callable_as<Func, void(T&)>>>
ifExists(Func && f)222 void ifExists(Func&& f) {
223 if (hasInstance()) {
224 f(*asT());
225 }
226 }
227
228 template <class Func, class = enable_if<is_callable_as<Func, void()>>>
229 void ifExists(Func&& f, void* = nullptr) {
230 if (hasInstance()) {
231 f();
232 }
233 }
234
235 private:
asT()236 T* asT() const { return reinterpret_cast<T*>(&mStorage); }
237
construct()238 void construct() const {
239 using TupleType =
240 typename std::decay<decltype(mCtorArgsGetter())>::type;
241 constexpr int tupleSize = std::tuple_size<TupleType>::value;
242 constructImpl(MakeSeqT<tupleSize>());
243 }
244 template <int... S>
constructImpl(Seq<S...>)245 void constructImpl(Seq<S...>) const {
246 auto args = mCtorArgsGetter();
247 (void)args;
248 new (&mStorage) T(std::move(std::get<S>(std::move(args)))...);
249 }
250
251 using StorageT =
252 typename std::aligned_storage<sizeof(T),
253 std::alignment_of<T>::value>::type;
254
255 alignas(double) mutable State mState = {};
256 mutable StorageT mStorage;
257 mutable CtorArgsGetter mCtorArgsGetter;
258 };
259
260 // A type alias to simplify defining an OnDemand<> object that will only be
261 // created from a list of constructor arguments.
262 template <class T, class... Args>
263 using OnDemandT = OnDemand<T, internal::TupleHolder<Args...>>;
264
265 // A type alias for defining an OnDemand<> object that needs to be class member
266 // but must delay constructor parameter evaluation.
267 // This one has a slight overhead of converting the ArgsGetter to std::function
268 // even if it was a lambda or some struct.
269 template <class T, class... Args>
270 using MemberOnDemandT = OnDemand<T, std::function<std::tuple<Args...>()>>;
271
272 // A version of OnDemand that's safe to initialize/destroy from multiple
273 // threads.
274 template <class T, class... Args>
275 using AtomicOnDemandT = OnDemand<T,
276 internal::TupleHolder<Args...>,
277 internal::LazyInstanceState>;
278 template <class T, class... Args>
279 using AtomicMemberOnDemandT = OnDemand<T,
280 std::function<std::tuple<Args...>()>,
281 internal::LazyInstanceState>;
282
283 // makeOnDemand() - factory functions for simpler OnDemand<> object creation,
284 // either from argument list or from a factory function.
285
286 // SimpleArgsGetter() returns a single value which is the only constructor
287 // argument for T.
288 template <class T,
289 class SimpleArgsGetter,
290 class = enable_if_c<
291 is_callable_with_args<SimpleArgsGetter, void()>::value &&
292 !is_template_instantiation_of<
293 decltype(std::declval<SimpleArgsGetter>()()),
294 std::tuple>::value>>
makeOnDemand(SimpleArgsGetter && getter)295 OnDemand<T, internal::TupleCreator<SimpleArgsGetter>> makeOnDemand(
296 SimpleArgsGetter&& getter) {
297 return {internal::TupleCreator<SimpleArgsGetter>(std::move(getter))};
298 }
299
300 // ArgsGetter() returns a tuple of constructor arguments for T.
301 template <
302 class T,
303 class ArgsGetter,
304 class = enable_if_c<is_callable_with_args<ArgsGetter, void()>::value &&
305 is_template_instantiation_of<
306 decltype(std::declval<ArgsGetter>()()),
307 std::tuple>::value>>
makeOnDemand(ArgsGetter && getter)308 OnDemand<T, ArgsGetter> makeOnDemand(ArgsGetter&& getter) {
309 return {std::move(getter)};
310 }
311
312 template <class T>
makeOnDemand()313 OnDemandT<T> makeOnDemand() {
314 return {{}};
315 }
316
317 template <class T,
318 class Arg0,
319 class = enable_if_c<!is_callable_with_args<Arg0, void()>::value>>
makeOnDemand(Arg0 && arg0)320 OnDemandT<T, Arg0> makeOnDemand(Arg0&& arg0) {
321 return {internal::TupleHolder<Arg0>{std::make_tuple(arg0)}};
322 }
323
324 template <class T, class Arg0, class Arg1, class... Args>
makeOnDemand(Arg0 && arg0,Arg1 && arg1,Args &&...args)325 OnDemandT<T, Arg0, Arg1, Args...> makeOnDemand(Arg0&& arg0,
326 Arg1&& arg1,
327 Args&&... args) {
328 return {internal::TupleHolder<Arg0, Arg1, Args...>{
329 std::make_tuple(arg0, arg1, args...)}};
330 }
331
332 template <class T>
makeAtomicOnDemand()333 AtomicOnDemandT<T> makeAtomicOnDemand() {
334 return {{}};
335 }
336
337 template <class T,
338 class Arg0,
339 class = enable_if_c<!is_callable_with_args<Arg0, void()>::value>>
makeAtomicOnDemand(Arg0 && arg0)340 AtomicOnDemandT<T, Arg0> makeAtomicOnDemand(Arg0&& arg0) {
341 return {internal::TupleHolder<Arg0>{std::make_tuple(arg0)}};
342 }
343
344 template <class T, class Arg0, class Arg1, class... Args>
makeAtomicOnDemand(Arg0 && arg0,Arg1 && arg1,Args &&...args)345 AtomicOnDemandT<T, Arg0, Arg1, Args...> makeAtomicOnDemand(Arg0&& arg0,
346 Arg1&& arg1,
347 Args&&... args) {
348 return {internal::TupleHolder<Arg0, Arg1, Args...>{
349 std::make_tuple(arg0, arg1, args...)}};
350 }
351
352 } // namespace base
353 } // namespace android
354