Fix emulator build error
[platform/framework/web/chromium-efl.git] / base / scoped_generic.h
1 // Copyright 2014 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef BASE_SCOPED_GENERIC_H_
6 #define BASE_SCOPED_GENERIC_H_
7
8 #include <stdlib.h>
9
10 #include <type_traits>
11
12 #include "base/check.h"
13 #include "base/memory/raw_ptr.h"
14
15 namespace base {
16
17 // This class acts like unique_ptr with a custom deleter (although is slightly
18 // less fancy in some of the more escoteric respects) except that it keeps a
19 // copy of the object rather than a pointer, and we require that the contained
20 // object has some kind of "invalid" value.
21 //
22 // Defining a scoper based on this class allows you to get a scoper for
23 // non-pointer types without having to write custom code for set, reset, and
24 // move, etc. and get almost identical semantics that people are used to from
25 // unique_ptr.
26 //
27 // It is intended that you will typedef this class with an appropriate deleter
28 // to implement clean up tasks for objects that act like pointers from a
29 // resource management standpoint but aren't, such as file descriptors and
30 // various types of operating system handles. Using unique_ptr for these
31 // things requires that you keep a pointer to the handle valid for the lifetime
32 // of the scoper (which is easy to mess up).
33 //
34 // For an object to be able to be put into a ScopedGeneric, it must support
35 // standard copyable semantics and have a specific "invalid" value. The traits
36 // must define a free function and also the invalid value to assign for
37 // default-constructed and released objects.
38 //
39 //   struct FooScopedTraits {
40 //     // It's assumed that this is a fast inline function with little-to-no
41 //     // penalty for duplicate calls. This must be a static function even
42 //     // for stateful traits.
43 //     static int InvalidValue() {
44 //       return 0;
45 //     }
46 //
47 //     // This free function will not be called if f == InvalidValue()!
48 //     static void Free(int f) {
49 //       ::FreeFoo(f);
50 //     }
51 //   };
52 //
53 //   using ScopedFoo = ScopedGeneric<int, FooScopedTraits>;
54 //
55 // A Traits type may choose to track ownership of objects in parallel with
56 // ScopedGeneric. To do so, it must implement the Acquire and Release methods,
57 // which will be called by ScopedGeneric during ownership transfers and extend
58 // the ScopedGenericOwnershipTracking tag type.
59 //
60 //   struct BarScopedTraits : public ScopedGenericOwnershipTracking {
61 //     using ScopedGenericType = ScopedGeneric<int, BarScopedTraits>;
62 //     static int InvalidValue() {
63 //       return 0;
64 //     }
65 //
66 //     static void Free(int b) {
67 //       ::FreeBar(b);
68 //     }
69 //
70 //     static void Acquire(const ScopedGenericType& owner, int b) {
71 //       ::TrackAcquisition(b, owner);
72 //     }
73 //
74 //     static void Release(const ScopedGenericType& owner, int b) {
75 //       ::TrackRelease(b, owner);
76 //     }
77 //   };
78 //
79 //   using ScopedBar = ScopedGeneric<int, BarScopedTraits>;
80 struct ScopedGenericOwnershipTracking {};
81
82 template<typename T, typename Traits>
83 class ScopedGeneric {
84  private:
85   // This must be first since it's used inline below.
86   //
87   // Use the empty base class optimization to allow us to have a D
88   // member, while avoiding any space overhead for it when D is an
89   // empty class.  See e.g. http://www.cantrip.org/emptyopt.html for a good
90   // discussion of this technique.
91   struct Data : public Traits {
92     explicit Data(const T& in) : generic(in) {}
93     Data(const T& in, const Traits& other) : Traits(other), generic(in) {}
94     T generic;
95   };
96
97  public:
98   typedef T element_type;
99   typedef Traits traits_type;
100
101   ScopedGeneric() : data_(traits_type::InvalidValue()) {}
102
103   // Constructor. Takes responsibility for freeing the resource associated with
104   // the object T.
105   explicit ScopedGeneric(const element_type& value) : data_(value) {
106     TrackAcquire(data_.generic);
107   }
108
109   // Constructor. Allows initialization of a stateful traits object.
110   ScopedGeneric(const element_type& value, const traits_type& traits)
111       : data_(value, traits) {
112     TrackAcquire(data_.generic);
113   }
114
115   // Move constructor. Allows initialization from a ScopedGeneric rvalue.
116   ScopedGeneric(ScopedGeneric<T, Traits>&& rvalue)
117       : data_(rvalue.release(), rvalue.get_traits()) {
118     TrackAcquire(data_.generic);
119   }
120   ScopedGeneric(const ScopedGeneric&) = delete;
121   ScopedGeneric& operator=(const ScopedGeneric&) = delete;
122
123   virtual ~ScopedGeneric() {
124     CHECK(!receiving_);  // ScopedGeneric destroyed with active receiver.
125     FreeIfNecessary();
126   }
127
128   // operator=. Allows assignment from a ScopedGeneric rvalue.
129   ScopedGeneric& operator=(ScopedGeneric<T, Traits>&& rvalue) {
130     reset(rvalue.release());
131     return *this;
132   }
133
134   // Frees the currently owned object, if any. Then takes ownership of a new
135   // object, if given. Self-resets are not allowd as on unique_ptr. See
136   // http://crbug.com/162971
137   void reset(const element_type& value = traits_type::InvalidValue()) {
138     if (data_.generic != traits_type::InvalidValue() && data_.generic == value)
139       abort();
140     FreeIfNecessary();
141     data_.generic = value;
142     TrackAcquire(value);
143   }
144
145   // Release the object. The return value is the current object held by this
146   // object. After this operation, this object will hold a null value, and
147   // will not own the object any more.
148   [[nodiscard]] element_type release() {
149     element_type old_generic = data_.generic;
150     data_.generic = traits_type::InvalidValue();
151     TrackRelease(old_generic);
152     return old_generic;
153   }
154
155   // A helper class that provides a T* that can be used to take ownership of
156   // a value returned from a function via out-parameter. When the Receiver is
157   // destructed (which should usually be at the end of the statement in which
158   // receive is called), ScopedGeneric::reset() will be called with the
159   // Receiver's value.
160   //
161   // In the simple case of a function that assigns the value before it returns,
162   // C++'s lifetime extension can be used as follows:
163   //
164   //    ScopedFoo foo;
165   //    bool result = GetFoo(ScopedFoo::Receiver(foo).get());
166   //
167   // Note that the lifetime of the Receiver is extended until the semicolon,
168   // and ScopedGeneric is assigned the value upon destruction of the Receiver,
169   // so the following code would not work:
170   //
171   //    // BROKEN!
172   //    ScopedFoo foo;
173   //    UseFoo(&foo, GetFoo(ScopedFoo::Receiver(foo).get()));
174   //
175   // In more complicated scenarios, you may need to provide an explicit scope
176   // for the Receiver, as in the following:
177   //
178   //    std::vector<ScopedFoo> foos(64);
179   //
180   //    {
181   //      std::vector<ScopedFoo::Receiver> foo_receivers;
182   //      for (auto foo : foos) {
183   //        foo_receivers_.emplace_back(foo);
184   //      }
185   //      for (auto receiver : foo_receivers) {
186   //        SubmitGetFooRequest(receiver.get());
187   //      }
188   //      WaitForFooRequests();
189   //    }
190   //    UseFoos(foos);
191   class Receiver {
192    public:
193     explicit Receiver(ScopedGeneric& parent) : scoped_generic_(&parent) {
194       // Check if we attempted to construct a Receiver for ScopedGeneric with an
195       // existing Receiver.
196       CHECK(!scoped_generic_->receiving_);
197       scoped_generic_->receiving_ = true;
198     }
199     Receiver(const Receiver&) = delete;
200     Receiver& operator=(const Receiver&) = delete;
201     Receiver(Receiver&& move) {
202       CHECK(!used_);       // Moving into already-used Receiver.
203       CHECK(!move.used_);  // Moving from already-used Receiver.
204       scoped_generic_ = move.scoped_generic_;
205       move.scoped_generic_ = nullptr;
206     }
207
208     Receiver& operator=(Receiver&& move) {
209       CHECK(!used_);       // Moving into already-used Receiver.
210       CHECK(!move.used_);  // Moving from already-used Receiver.
211       scoped_generic_ = move.scoped_generic_;
212       move.scoped_generic_ = nullptr;
213     }
214     ~Receiver() {
215       if (scoped_generic_) {
216         CHECK(scoped_generic_->receiving_);
217         scoped_generic_->reset(value_);
218         scoped_generic_->receiving_ = false;
219       }
220     }
221     // We hand out a pointer to a field in Receiver instead of directly to
222     // ScopedGeneric's internal storage in order to make it so that users can't
223     // accidentally silently break ScopedGeneric's invariants. This way, an
224     // incorrect use-after-scope-exit is more detectable by ASan or static
225     // analysis tools, as the pointer is only valid for the lifetime of the
226     // Receiver, not the ScopedGeneric.
227     T* get() {
228       used_ = true;
229       return &value_;
230     }
231
232    private:
233     T value_ = Traits::InvalidValue();
234     raw_ptr<ScopedGeneric<T, Traits>> scoped_generic_;
235     bool used_ = false;
236   };
237
238   const element_type& get() const { return data_.generic; }
239
240   // Returns true if this object doesn't hold the special null value for the
241   // associated data type.
242   bool is_valid() const { return data_.generic != traits_type::InvalidValue(); }
243
244   bool operator==(const element_type& value) const {
245     return data_.generic == value;
246   }
247   bool operator!=(const element_type& value) const {
248     return data_.generic != value;
249   }
250
251   Traits& get_traits() { return data_; }
252   const Traits& get_traits() const { return data_; }
253
254  private:
255   void FreeIfNecessary() {
256     if (data_.generic != traits_type::InvalidValue()) {
257       TrackRelease(data_.generic);
258       data_.Free(data_.generic);
259       data_.generic = traits_type::InvalidValue();
260     }
261   }
262
263   template <typename Void = void>
264   typename std::enable_if_t<
265       std::is_base_of_v<ScopedGenericOwnershipTracking, Traits>,
266       Void>
267   TrackAcquire(const T& value) {
268     if (value != traits_type::InvalidValue()) {
269       data_.Acquire(static_cast<const ScopedGeneric&>(*this), value);
270     }
271   }
272
273   template <typename Void = void>
274   typename std::enable_if_t<
275       !std::is_base_of_v<ScopedGenericOwnershipTracking, Traits>,
276       Void>
277   TrackAcquire(const T& value) {}
278
279   template <typename Void = void>
280   typename std::enable_if_t<
281       std::is_base_of_v<ScopedGenericOwnershipTracking, Traits>,
282       Void>
283   TrackRelease(const T& value) {
284     if (value != traits_type::InvalidValue()) {
285       data_.Release(static_cast<const ScopedGeneric&>(*this), value);
286     }
287   }
288
289   template <typename Void = void>
290   typename std::enable_if_t<
291       !std::is_base_of_v<ScopedGenericOwnershipTracking, Traits>,
292       Void>
293   TrackRelease(const T& value) {}
294
295   // Forbid comparison. If U != T, it totally doesn't make sense, and if U ==
296   // T, it still doesn't make sense because you should never have the same
297   // object owned by two different ScopedGenerics.
298   template <typename T2, typename Traits2> bool operator==(
299       const ScopedGeneric<T2, Traits2>& p2) const;
300   template <typename T2, typename Traits2> bool operator!=(
301       const ScopedGeneric<T2, Traits2>& p2) const;
302
303   Data data_;
304   bool receiving_ = false;
305 };
306
307 template<class T, class Traits>
308 void swap(const ScopedGeneric<T, Traits>& a,
309           const ScopedGeneric<T, Traits>& b) {
310   a.swap(b);
311 }
312
313 template<class T, class Traits>
314 bool operator==(const T& value, const ScopedGeneric<T, Traits>& scoped) {
315   return value == scoped.get();
316 }
317
318 template<class T, class Traits>
319 bool operator!=(const T& value, const ScopedGeneric<T, Traits>& scoped) {
320   return value != scoped.get();
321 }
322
323 }  // namespace base
324
325 #endif  // BASE_SCOPED_GENERIC_H_