• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Flutter 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 FLUTTER_FML_UNIQUE_OBJECT_H_
6 #define FLUTTER_FML_UNIQUE_OBJECT_H_
7 
8 #include <utility>
9 
10 #include "flutter/fml/compiler_specific.h"
11 #include "flutter/fml/logging.h"
12 #include "flutter/fml/macros.h"
13 
14 namespace fml {
15 
16 // struct UniqueFooTraits {
17 //   // This function should be fast and inline.
18 //   static int InvalidValue() { return 0; }
19 //
20 //   // This function should be fast and inline.
21 //   static bool IsValid(const T& value) { return value != InvalidValue(); }
22 //
23 //   // This free function will not be called if f == InvalidValue()!
24 //   static void Free(int f) { ::FreeFoo(f); }
25 // };
26 
27 template <typename T, typename Traits>
28 class UniqueObject {
29  private:
30   // This must be first since it's used inline below.
31   //
32   // Use the empty base class optimization to allow us to have a Traits
33   // member, while avoiding any space overhead for it when Traits is an
34   // empty class.  See e.g. http://www.cantrip.org/emptyopt.html for a good
35   // discussion of this technique.
36   struct Data : public Traits {
DataData37     explicit Data(const T& in) : generic(in) {}
DataData38     Data(const T& in, const Traits& other) : Traits(other), generic(in) {}
39 
40     T generic;
41   };
42 
43  public:
44   using element_type = T;
45   using traits_type = Traits;
46 
UniqueObject()47   UniqueObject() : data_(Traits::InvalidValue()) {}
UniqueObject(const T & value)48   explicit UniqueObject(const T& value) : data_(value) {}
49 
UniqueObject(const T & value,const Traits & traits)50   UniqueObject(const T& value, const Traits& traits) : data_(value, traits) {}
51 
UniqueObject(UniqueObject && other)52   UniqueObject(UniqueObject&& other)
53       : data_(other.release(), other.get_traits()) {}
54 
~UniqueObject()55   ~UniqueObject() { FreeIfNecessary(); }
56 
57   UniqueObject& operator=(UniqueObject&& other) {
58     reset(other.release());
59     return *this;
60   }
61 
62   void reset(const T& value = Traits::InvalidValue()) {
63     FML_CHECK(data_.generic == Traits::InvalidValue() ||
64               data_.generic != value);
65     FreeIfNecessary();
66     data_.generic = value;
67   }
68 
swap(UniqueObject & other)69   void swap(UniqueObject& other) {
70     // Standard swap idiom: 'using std::swap' ensures that std::swap is
71     // present in the overload set, but we call swap unqualified so that
72     // any more-specific overloads can be used, if available.
73     using std::swap;
74     swap(static_cast<Traits&>(data_), static_cast<Traits&>(other.data_));
75     swap(data_.generic, other.data_.generic);
76   }
77 
78   // Release the object. The return value is the current object held by this
79   // object. After this operation, this object will hold an invalid value, and
80   // will not own the object any more.
release()81   T release() FML_WARN_UNUSED_RESULT {
82     T old_generic = data_.generic;
83     data_.generic = Traits::InvalidValue();
84     return old_generic;
85   }
86 
get()87   const T& get() const { return data_.generic; }
88 
is_valid()89   bool is_valid() const { return Traits::IsValid(data_.generic); }
90 
91   bool operator==(const T& value) const { return data_.generic == value; }
92 
93   bool operator!=(const T& value) const { return data_.generic != value; }
94 
get_traits()95   Traits& get_traits() { return data_; }
get_traits()96   const Traits& get_traits() const { return data_; }
97 
98  private:
FreeIfNecessary()99   void FreeIfNecessary() {
100     if (data_.generic != Traits::InvalidValue()) {
101       data_.Free(data_.generic);
102       data_.generic = Traits::InvalidValue();
103     }
104   }
105 
106   // Forbid comparison. If U != T, it totally doesn't make sense, and if U ==
107   // T, it still doesn't make sense because you should never have the same
108   // object owned by two different UniqueObject.
109   template <typename T2, typename Traits2>
110   bool operator==(const UniqueObject<T2, Traits2>& p2) const = delete;
111 
112   template <typename T2, typename Traits2>
113   bool operator!=(const UniqueObject<T2, Traits2>& p2) const = delete;
114 
115   Data data_;
116 
117   FML_DISALLOW_COPY_AND_ASSIGN(UniqueObject);
118 };
119 
120 template <class T, class Traits>
swap(const UniqueObject<T,Traits> & a,const UniqueObject<T,Traits> & b)121 void swap(const UniqueObject<T, Traits>& a, const UniqueObject<T, Traits>& b) {
122   a.swap(b);
123 }
124 
125 template <class T, class Traits>
126 bool operator==(const T& value, const UniqueObject<T, Traits>& object) {
127   return value == object.get();
128 }
129 
130 template <class T, class Traits>
131 bool operator!=(const T& value, const UniqueObject<T, Traits>& object) {
132   return !(value == object.get());
133 }
134 
135 }  // namespace fml
136 
137 #endif  // FLUTTER_FML_UNIQUE_OBJECT_H_
138