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