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